Reputation: 5817
On the Try F# website they give an example of a computation expression:
type Age =
| PossiblyAlive of int
| NotAlive
type AgeBuilder() =
member this.Bind(x, f) =
match x with
| PossiblyAlive(x) when x >= 0 && x <= 120 -> f(x)
| _ -> NotAlive
member this.Delay(f) = f()
member this.Return(x) = PossiblyAlive x
let age = new AgeBuilder()
let willBeThere (a:int) (y:int) =
age {
let! current = PossiblyAlive a
let! future = PossiblyAlive (current + y)
return future
}
which seems a bit like the standard Maybe monad found in Haskell.
However, in true Haskell form I would want to use return for the two lines:
let! current = PossiblyAlive a
let! future = PossiblyAlive (current + y)
to be:
let! current = return a
let! future = return (current + y)
however it doesn't work. The closest I get to is:
let! current = age.Return a
let! future = age.Return (current + y)
but this looks dirty. Is there any way to use return
without using the computation builders function explicitly?
Upvotes: 1
Views: 212
Reputation: 5817
I have had a look at this problem in more detail and I think I have found a reasonable alternative to using the age { return <expr> }
syntax that Lee shows in his answer.
My main beef with this syntax is that we are already in the age
monad therefore any return
statement within the body ought to resolve automatically to age.Return
. However, fixing this is probably of very low priority for the F# team, because the workaround is extremely simple.
My alternative is to overload the Bind
method with a function which takes a value which it then lifts; then sends this lifted value to the other Bind
function:
type Age =
| PossiblyAlive of int
| NotAlive
type AgeBuilder() =
let reasonableAge (x:int) = x >= 0 && x <= 120
member __.Return x =
if reasonableAge x then PossiblyAlive x else NotAlive
member __.Bind(x:Age, f) =
match x with
| PossiblyAlive x when reasonableAge x -> f x
| _ -> NotAlive
member this.Bind(x:int, f) =
this.Bind(this.Return(x), f)
let age = new AgeBuilder()
let willBeThere (a:int) (y:int) =
age {
let! current = a
let! future = (current + y)
return future
}
Upvotes: 0
Reputation: 144206
You can create a nested expression:
let! current = age { return a }
let! future = age { return (current + y) }
although you could just use let
instead:
let current = a
let future = current + y
Be aware that this builder breaks the monad laws since
return 150 >>= return
is not the same as return 150
Upvotes: 3