Why can't I use pattern matching function
in computation expressions without implement Zero
member?
For example, could somepone explain why it permits allowing pattern matching expression
but not pattern matching function
?
type MaybeBuilder() =
member __.Bind (x, f) = match x with Some a -> f a | None -> None
member __.Return x = Some x
let maybe = MaybeBuilder()
// Errors: FS0708 This control construct may only be used
// if the computation expression builder defines a 'Zero' method
maybe { Some 1 |> function Some x -> return x | None -> return 0 }
maybe { Some 1 |> fun x -> match x with Some x' -> return x' | None -> return 0 }
// Ok
maybe { match Some 1 with Some x -> return x | None -> return 0 }
This error seems to be an effect of a subtle issue with your example. When you write maybe { Some 1 |> function Some x -> return x | None -> return 0 }
, it's equivalent to the following code
let expr1 = function Some x -> return x | None -> return 0
let expr2 = Some 1 |> expr1
maybe { expr2 }
which shows that
return
for the result of expr2
, so the compiler can only guess that is what you want, and asks for Zero()
method to give the value of the result of maybe { expr2 }
, andreturn
calls that you have there are used in a wrong scope (and if you split your code like this, compiler will complain) so even if you implement Zero()
, it won't compile.To fix that, you can rewrite the functions as
maybe { return Some 1 |> function Some x -> x | None -> 0 }
or you can add the maybe
computation expression inside the branches of expr1
function. It looks bad in this example, but may be viable for more complicated logic that may not all be in the context of maybe { }
builder
Some 1 |> function Some x -> maybe { return x } | None -> maybe { return 0 }