6.3.10 计算表达式
更具体地说,计算表达式的形式为builder-expr { cexpr },其中cexpr在语法上是表达式的语法结构,并定义了comp-expr中的附加构造。计算表达式用于序列和其他F#表达式语法的非标准解释。表达式builder-expr { cexpr }的翻译如下:
let b = builder-expr in b.Run (b.Delay(fun () -> {| cexpr |}C))
Run
方法是在开发过程中添加的,所以它可能没有出现在文档中的原因。正如desco所解释的那样,该方法用于“运行”计算表达式。这意味着无论何时编写expr { ... }
,翻译后的代码将被包装在对Run
的调用中。expr { let! a = foo() expr { let! c = expr {
let! b = bar(a) let! a = foo()
let! c = woo(b) let! b = bar(a)
return! zoo(c) } return! woo(b) }
return! zoo(c) }
Run
方法仅在整体结果上调用一次,在右侧则调用两次(对于整体计算表达式和嵌套的计算表达式)。该方法通常的类型签名为M<T> -> T
,这意味着右侧代码甚至无法编译。Run
方法破坏了单子的某些良好方面。但是,如果你知道你在做什么,那么它可以很有用...break
代码中,计算生成器立即执行其主体(在声明中),因此添加Run
以取消包装结果不会破坏组合性 - 组合只是运行另一个代码。然而,为async
和其他延迟计算定义Run
根本不是一个好主意。Run
有一个类型为M<T> -> M<T>
- 通常会破坏兼容性的情况是像M<T> -> T
这样的(例如,当计算生成器创建任务并启动它时)。 - Tomas Petricek