.net 何时在计算表达式中实现'Zero'成员?

.net 何时在计算表达式中实现'Zero'成员?,.net,f#,functional-programming,monads,computation-expression,.net,F#,Functional Programming,Monads,Computation Expression,为什么我不能在没有implementZero成员的计算表达式中使用模式匹配函数 例如,有人能解释为什么它允许模式匹配表达式,但不允许模式匹配函数 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

为什么我不能在没有implement
Zero
成员的计算表达式中使用
模式匹配函数

例如,有人能解释为什么它允许
模式匹配表达式
,但不允许
模式匹配函数

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 }

这个错误似乎是您的示例中的一个微妙问题造成的。当您编写
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 }
这表明

  • 对于
    expr2
    的结果,您没有调用
    return
    ,因此编译器只能猜测您想要的结果,并要求
    Zero()
    方法给出
    的结果值,可能是{expr2}
    ,以及
  • 您在那里使用的
    return
    调用在错误的作用域中使用(如果您像这样拆分代码,编译器会抱怨),因此即使您实现
    Zero()
    ,它也不会编译
  • 要解决这个问题,可以将函数重写为

    maybe { return Some 1 |> function Some x -> x | None -> 0 }
    
    或者您可以在
    expr1
    函数的分支中添加
    计算表达式。在本例中,它看起来很糟糕,但对于更复杂的逻辑来说可能是可行的,因为这些逻辑可能并不都在
    maybe{}
    builder的上下文中

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

    你是否尝试过实现一个
    Zero
    方法,看看会发生什么?我希望你会感到惊讶-问题可能不是你所期望的。