没有 for..in..do 的扩展计算表达式

2023-12-21

我所说的扩展计算表达式是指具有通过定义的自定义关键字的计算表达式定制操作 http://msdn.microsoft.com/en-us/library/hh289709.aspx属性。

当阅读有关扩展计算表达式 http://files.meetup.com/2922732/Computation%20Expressions%20%28April%29.pdf,我遇到了 @kvb 的非常酷的 IL DSL:

let il = ILBuilder()

// will return 42 when called
// val fortyTwoFn : (unit -> int)
let fortyTwoFn = 
    il {
        ldc_i4 6
        ldc_i4_0
        ldc_i4 7
        add
        mul
        ret
    }

我想知道这些操作如何在不使用的情况下组成for..in..do构造。我的直觉是它开始于x.Zero会员,但我还没有找到任何参考资料来验证这一点。

如果上面的示例技术性太强,这里有一个类似的 DSL,其中列出了幻灯片的组件,但没有列出for..in..do:

page {
      title "Happy New Year F# community"
      item "May F# continue to shine as it did in 2012"
      code @"…"
      button (…)
} |> SlideShow.show

我有几个密切相关的问题:

  • 如何定义或使用扩展计算表达式而不需要For成员(即提供一个完整的小例子)?如果它们不再是 monad,我不太担心,我对它们开发 DSL 感兴趣。
  • 我们可以使用扩展计算表达式吗let! and return!?如果是的话,还有什么理由不这样做吗?我问这些问题是因为我还没有遇到任何使用的例子let! and return!.

我很高兴您喜欢 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

现在,您的计算表达式将计算为其脱糖形式的引用。这在调试时非常方便。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

没有 for..in..do 的扩展计算表达式 的相关文章

随机推荐