计算表达式中的归零和合并

Zero and Combine in Computation Expression

我有以下计算表达式构建器:

type ExprBuilder() = 
    member this.Return(x) =
        Some x

let expr = new ExprBuilder()

我了解方法 ReturnZeroCombine 的用途,但我不明白下面显示的表达式之间有什么区别:

let a = expr{
    printfn "Hello"
    return 1
} // result is Some 1

let c = expr{
   return 1
   printfn "Hello"
} // do not compile. Combine method required

我也不明白为什么在第一种情况下 Zero 方法不需要 printfn 语句?

在第一个表达式中,您执行了一些产生值 1 的计算,仅此而已。你不需要 Zero ,因为 Zero 只需要 return-less 表达式(这就是为什么它被称为 "zero" - 它是什么都没有的东西那里),并且您的表达式确实有一个 return.

为了明确回答您的问题,Zero 不是必需的“for the printfn statement”,因为并非表达式中的每一行都被转换。在编译计算表达式时,编译器会在 "special" 个点将它们打散,例如 let!do!return 等,将所有其余代码留在它们之间点完好无损。在这种情况下,您的 printfn 调用只是成为 return.

之前执行的代码的一部分

在第二个表达式中,您执行 两次 计算:第一个计算结果为 1,第二个计算结果为 Zero(即当表达式缺少 return 时隐式假定)。但是整个计算表达式不能有两个 return 值,它必须有一个。因此,为了将两个计算的结果放在一起(有人可能会说 combine 它们),您需要 Combine 方法。

除了 CombineZero,您还需要实施 Delay 才能正常工作。多部分(即 "combined")计算也包含在 Delay 中,以允许构建器推迟评估并可能在 Combine 实现中删除一些部分。

我建议通读 this introduction by Scott Wlaschin, specifically part 3 about Delay and Run