views:

191

answers:

3

I'm using F# v 1.9.6.2, and I've defined a very simple computation expression:

type MaybeBuilder() =
    member this.Let(x, f) =
        printfn "this.Let: %A" x
        this.Bind(Some x, f)
    member this.Bind(x, f) =
        printfn "this.Bind: %A" x
        match x with
        | Some(x) when x >= 0 && x <= 100 -> f(x)
        | _ -> None
    member this.Delay(f) = f()
    member this.Return(x) = Some x

let maybe = MaybeBuilder()

I've sprinkled some print statements in the code to tell me which methods are being called in a computation expression. When I execute the following statement:

maybe {
    let x = 12
    let! y = Some 11
    let! z = Some 30
    return x + y + z
}

I expect the console to print out the following:

this.Let 12
this.Bind Some 12
this.Bind Some 11
this.Bind Some 30

But my actual results are as follows:

this.Bind: Some 11
this.Bind: Some 30

In other words, F# doesn't appear to be executing the Let member. When I re-write Let to throw an exception, the code run without an exception. Additionally, when I comment out the Let member entirely, I do not get an error message stating The field, constructor or member 'Let' is not defined, and the code executes as expected.

(I've tried investigating the code with Reflector, but as is usually the case, decompiled F# is mangled beyond readability.)

It looks like the spec for computation expressions has changed. Are let bindings no longer treated as syntax sugar, and is the Let members no longer required in computation workflows?

+1  A: 

You had the answer yourself. From the F# spec that describes how computation expressions are translated:

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

So no, you don't need to define let explicitly anymore, it's translated by the compiler.

Update: this change is mentioned in the detailed release notes of the September CTP.

Kurt Schelfthout
Thank you :) I actually read through those release notes prior to posting my question, but wasn't entirely sure since 100% of examples demonstrating the maybe monad define a Let member.
Juliet
A: 

Correct -- you can no longer provide a binding for let :(.

MichaelGG
Why the sad face? I mean, I can see you lose some flexibility, but did you have a use case for it? At first sight, it looks more confusing than useful.
Kurt Schelfthout
I don't think its a bad thing, I personally don't like the idea of redefining the meaning of let.
Juliet
Well last time I checked into it (months ago), was to write a combo workflow that did some "async" (specific to the app) as well as had early termination possibilities on every executed statement. Not hard to work around, just would have been cute. I certainly haven't analysed it like the F# has :).
MichaelGG
A: 

See also http://cs.hubfs.net/forums/thread/6950.aspx

Brian