Hi yashez,
it look like this behaviour is specific to the F# CTP.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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:

1
2
3
          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:
1
2
3
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

By on 9/7/2008 3:16 PM ()

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

From the spec ([link:research.microsoft.com])

1
2
3
4
5
6
7
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).

By on 9/7/2008 3:30 PM ()

Thanks brianmcn and DannyAsher for your answers.

Two last questions:

1. Why this change in CTP?

2. What changes in the de-sugaring process?

By on 9/7/2008 5:27 PM ()

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...

By on 9/8/2008 12:41 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper