hubFS: THE place for F#

. . . are you on The Hub?
Welcome to hubFS: THE place for F# Sign in | Join | Help
in Search

Workflow question

Last post 09-08-2008, 0:41 by brianmcn. 4 replies.
Sort Posts: Previous Next
  •  09-07-2008, 6:55 6950

    Workflow question

    Hi,

    After reading this article about workflows, I tried to implement something similar myself.

    I came up with the following code:

    type 'a Script = (unit -> 'a)

    let runScript (a: 'a Script) = a()
    let delay f = fun () -> runScript (f ())

    type ScriptBuilder() =
    member b.Return(x) =
    printfn "Return (%A)" x
    fun() -> x
    member b.Let(p, rest) : 'a Script =
    printfn "Let (%A)" p
    rest p
    member b.Bind(p, rest) : 'a Script =
    printfn "Bind (%A)" p
    rest p
    member b.Delay(f) =
    printfn "Delay"
    delay f

    let script = new ScriptBuilder()


    However, when I run this snippet:

    let num = script { let x = 2
    let! y = 21
    return x * y }

    runScript num |> ignore


    I don't see "Let (2)" printed. It's like if ScriptBuilder.Let never gets called.

    Does anyone understand why? I'm using F# CTP 1.9.6.0

    Thanks a lot for your help!

    EDIT: I have tried several other monads and Builder.Let is never called (?!)
  •  09-07-2008, 15:16 6955 in reply to 6950

    Re: Workflow question


    Hi yashez,

    it look like this behaviour is specific to the F# CTP.
    type 'a Script = (unit -> 'a)
    let runScript (a: 'a Script) = a()
    let delay f = fun () -> runScript (f ())
    type ScriptBuilder() =
    member b.Return(x) =
    printfn "Return (%A)" x
    fun() -> x
    member b.Bind(p, rest) : 'a Script =
    printfn "Bind (%A)" p
    rest p
    member b.Delay(f) =
    printfn "Delay"
    delay f
    let script = new ScriptBuilder()
    let num = script { let x = 2
    let! y = 21
    return x * y }
    I removed the b.Let function from the script above and it compiles a runs fine in the CTP but causes the following compile error in v1.9.4.19:

              let x = 2
      ----------------^^

    stdin(27,16): error FS0039: The field, constructor or member 'Let' is not defined.


    It seems as if the Let member is being ignored in the CTP. Perhaps this is related to the CTP item:

    Sequence and Computation Expression Syntax Regularization and Simplification

    • The full range of ‘let’ bindings are permitted in computation expressions. Let bindings in computation expressions now have the same syntax as in the rest of the F# langauge:
        let s2 = 
    async { let rec f x = f x + 1
    return 1 }

    I hope we can quickly verify if this is a compiler bug or whether the Let binding should be implemented differently.

    regards,

    Danny

  •  09-07-2008, 15:30 6956 in reply to 6955

    Re: Workflow question

    This is now By Design, "Let" is no longer a method for builders.

    From the spec (http://research.microsoft.com/fsharp/manual/spec2.aspx)

    6.4.10   Computation Expressions

    ...

    {| let binds in cexpr |}C                        = let binds in {| cexpr |}C)

    ...

    (though there is a misleading bit shortly afterwards in the spec, where an example is given that still defines the .Let() member - that part is a spec bug).

  •  09-07-2008, 17:27 6962 in reply to 6956

    Re: Workflow question

    Thanks brianmcn and DannyAsher for your answers.

    Two last questions:

    1. Why this change in CTP?
    2. What changes in the de-sugaring process?
  •  09-08-2008, 0:41 6965 in reply to 6962

    Re: Workflow question

    As DannyAsher pointed out in the release notes, this is motivated by being able to allow the full range of let expressions inside computation expressions (including defining functions e.g."let f x = ..." and recursive definitions "let rec ..."), which makes the language syntax more regular: before the CTP, the 'sublanguage' that could appear in computation expressions was more limited, whereas now most expression code that can be written outside a computation expression can also be written in it using the same syntax. (Additionally I don't think we had ever encountered any cases where it was important to 'replace the behavior of let' for a particular monad.)

    Regarding the desugaring, see the spec (section 6.4.10) that I referenced before, it has the complete desugaring rules for computation expressions.  I don't recall the differences from pre-CTP offhand... other than removal of b.Let(), I think there may be some other small changes to b.Combine() and how b.Zero() is used by some expressions...

View as RSS news feed in XML
Powered by Community Server, by Telligent Systems