我很高兴您喜欢 IL 示例。了解表达式如何脱糖的最好方法可能是查看spec http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc335818835(虽然有点浓……)。
在那里我们可以看到类似的东西
C {
op1
op2
}
脱糖如下:
T([<CustomOperator>]op1; [<CustomOperator>]op2, [], fun v -> v, true) ⇒
CL([<CustomOperator>]op1; [<CustomOperator>]op2, [], C.Yield(), false) ⇒
CL([<CustomOperator>]op2, [], 〚 [<CustomOperator>]op1, C.Yield() |][], false) ⇒
CL([<CustomOperator>]op2, [], C.Op1(C.Yield()), false) ⇒
〚 [<CustomOperator>]op2, C.Op1(C.Yield()) 〛[] ⇒
C.Op2(C.Op1(C.Yield()))
至于为什么Yield()
被使用而不是Zero
,这是因为如果范围内有变量(例如,因为您使用了一些lets
,或者处于 for 循环中,等等),那么你会得到Yield (v1,v2,...)
but Zero
显然不能这样使用。请注意,这意味着添加一个多余的let x = 1
进入托马斯的lr
示例将无法编译,因为Yield
将使用类型参数调用int
而不是unit
.
还有另一个技巧可以帮助理解计算表达式的编译形式,即(ab)使用 F# 3 中计算表达式的自动引用支持。只需定义一个不执行任何操作的函数Quote
会员并制作Run
只需返回其参数:
member __.Quote() = ()
member __.Run(q) = q
现在,您的计算表达式将计算为其脱糖形式的引用。这在调试时非常方便。