Computation Expressions

Category: visual studio fsharp


Captain Kernel on Sun, 04 Dec 2016 16:47:40

This is a quick question. I know that a workflow like "async" or "seq" are instances of underlying builder classes but where does the instantiation take place?

We - the developers - do not need to to instantiate an "AsyncBuilder()" or "SeqBuilder()" instance in order to use these, but they must be instantiated somehow.

Are they (implicitly) instantiated at the point they occur? if so why do I see examples where an instance is explicitly created?

(See the ScriptBuilder).

Why do I not need to ever instantiate an "async" or "seq"? In that example, must I instantiate a "script" every time I want to use one or does one instance somehow (like a singleton) serve all usages I may need?



Mr. Tines on Sun, 04 Dec 2016 19:52:44

There's a static singleton instance of the builder type in each case.  If you roll your own, as in

type OptionBuilder() =
    member self.Bind(input, operation) = Option.bind operation input
    member self.Delay (operation:(unit -> option<'TAny>)) = operation ()

    member self.Return input = Some input

    member self.ReturnFrom (input : option<'TAny>) = input

then you also need to declare the instance as in

module Monads =   
  let option = OptionBuilder()

Then in code which links this, you can write an option expression (trivial example which simply invokes OptionBuilder.ReturnFrom)

    let value : Option<string> = Some tag
    let result = option { return! value }
The name 'option' for the computation expression is precisely the name of that global static OptionBuilder instance.