何时在计算表达式中实现“零”成员?

时间:2018-01-12 15:16:54

标签: .net f# functional-programming monads computation-expression

为什么我不能在没有实现pattern matching function成员的计算表达式中使用Zero

例如,是否有人可以解释为什么允许pattern matching expression但不允许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 }

1 个答案:

答案 0 :(得分:3)

此错误似乎是您的示例的一个微妙问题的影响。当您编写maybe { Some 1 |> function Some x -> return x | None -> return 0 }时,它等同于以下代码

let expr1 = function Some x -> return x | None -> return 0
let expr2 = Some 1 |> expr1

maybe { expr2 }

显示

  1. 你没有为return的结果调用expr2,所以编译器只能猜测你想要的是什么,并要求Zero()方法给出值maybe { expr2 }
  2. 的结果
  3. 你在那里进行的return调用在错误的范围内使用(如果你像这样拆分代码,编译器会抱怨),所以即使你实现了Zero(),它也会赢得' t编译。
  4. 要解决此问题,您可以将功能重写为

    maybe { return Some 1 |> function Some x -> x | None -> 0 }
    

    或者您可以在maybe函数的分支内添加expr1计算表达式。在这个例子中它看起来很糟糕,但对于更复杂的逻辑可能是可行的,这些逻辑可能并非都在maybe { } builder

    的上下文中
    Some 1 |> function Some x -> maybe { return x } | None -> maybe { return 0 }