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?
-
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.
Juliet : 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. -
Correct -- you can no longer provide a binding for let :(.
Kurt Schelfthout : 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.Juliet : I don't think its a bad thing, I personally don't like the idea of redefining the meaning of let.MichaelGG : 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 :).
0 comments:
Post a Comment