Это должно быть легче объяснить, если мы посмотрим на минимальный пример, который реализует рабочий процесс, подобный этому.Сначала я определю тип для операций, которые вы можете выполнять.Для простоты давайте выберем только одно:
type Operation =
| WriteInt32 of int
Типичные компиляторы вычислений F # не принимают никаких параметров конструктора, но вы можете на самом деле принимать параметры - компоновщик вычислений здесь принимает поток в качестве параметра и создает StreamWriter
.В операции Bind
аргумент является одним из наших значений Operation
, и мы обрабатываем его, записывая значение в средство записи потока.Затем мы просто вызываем остальную часть вычисления, используя f ()
type BitWriter(stream:IO.Stream) =
let wr = new IO.StreamWriter(stream)
member x.Bind(op, f) =
match op with
| WriteInt32 i -> wr.Write(i)
f ()
member x.Zero() = ()
member x.Run( () ) = wr.Dispose()
Операции Zero
и Run
не особенно интересны, но для перевода требуется Zero
, а Run
позволяетмы распоряжаемся писателем.Это не самый идиоматический способ определения выражений вычислений - он не следует монадической структуре - но на самом деле он работает!Два помощника, прежде чем мы сможем его использовать:
let writeInt32 i = WriteInt32 i
let bitWriter stream = BitWriter(stream)
И теперь вы можете написать код, в значительной степени похожий на то, что делает вышеуказанная библиотека:
let stream = new IO.MemoryStream()
bitWriter stream {
do! writeInt32 1
do! writeInt32 2
do! writeInt32 3
}