NovelIO


Channels

Channels represent a mechanism of one or two way communication with some kind of resource, such as a file or remote server (e.g. via TCP).

Channels come in two flavours, a TChannel which supports text data and a BChannel which supports binary data, functions are provided in the TextChannel and BinaryChannel modules respectively.

Controlling lifetime

The typical method of controlling method of explicitly controlling lifetime in .NET is to use IDispoable, however this approach fundamentally relies on side-effects. NovelIO therefore uses a different approach: the bracket pattern.

bracket is a function supplied in the IO module: val bracket : IO<'a> -> ('a -> IO<'b>) -> ('a -> IO<'c>) -> IO<'c>.

The first argument is an action of type IO<'a> which creates a resource.

The second argument is a function which takes the resource created by the first action and cleans it up.

The third argument is a function which takes the resource created by the first action and returns a new action, this new action is then returned by the bracket function.

Put succinctly, there is a way of creating a resource, a way of cleaning it up and a function to happen in between.

Using the bracket pattern

In general, you don't need to worry about using 'bracket' explictly. Functions are created for different resources to avoid you having to fill out all of bracket's arguments manually.

An example is the File.withTextChannel function:

File.withTextChannel File.Open.defaultRead (File.Path.fromValid "test.txt") (fun channel ->
    io {
        let! l1 = TextChannel.getLine channel
        let! l2 = TextChannel.getLine channel
        return l1, l2
    })

By using the withTextChannel function, we can supply an argument of the form TChannel -> IO<'a> which determines what to do with the channel during its entire lifetime. This is equivalent to just the final argument of bracket where the two preceeding arguments are filled in for us.

with_ functions are provided throughout the library for other types of channels and resources but they follow the same pattern as described here.

namespace NovelFS
namespace NovelFS.NovelIO
module File

from NovelFS.NovelIO
val withTextChannel : options:FileOpenOptions -> fName:FilePath -> fChannel:(TChannel -> IO<'a>) -> IO<'a>

Full name: NovelFS.NovelIO.File.withTextChannel
module Open

from NovelFS.NovelIO.File
val defaultRead : FileOpenOptions

Full name: NovelFS.NovelIO.File.Open.defaultRead
module Path

from NovelFS.NovelIO.File
val fromValid : path:string -> FilePath

Full name: NovelFS.NovelIO.File.Path.fromValid
val channel : TChannel
val io : IO.IOBuilder

Full name: NovelFS.NovelIO.IOBuilders.io
val l1 : string
module TextChannel

from NovelFS.NovelIO
val getLine : channel:TChannel -> IO<string>

Full name: NovelFS.NovelIO.TextChannel.getLine
val l2 : string
Fork me on GitHub