没有for..in.do的扩展计算表达式 [英] Extended computation expressions without for..in..do

查看:66
本文介绍了没有for..in.do的扩展计算表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我所说的扩展计算表达式是指通过 CustomOperation定义的具有自定义关键字的计算表达式。 a>属性。

阅读扩展了计算表达式,我通过@kvb遇到了非常酷的IL DSL:

When reading about extended computation expressions, I come across very cool IL DSL by @kvb:

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 成员开头,但是我还没有找到任何引用来验证这一点。

I wonder how the operations compose without using for..in..do construct. My gut feeling is that it starts with x.Zero member, but I haven't found any reference to verify that.

如果上面的示例过于技术性,这是一个类似的DSL,其中列出了幻灯片的组件,而没有 for..in..do

If the example above is too technical, here is a similar DSL where components of a slide are listed without 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

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

I have a few closely related questions:


  • 如何在没有 For 成员的情况下定义或使用扩展计算表达式(即提供一个小的完整示例)? / em>我不再担心它们不再是单子了,我对它们开发DSL感兴趣。

  • 我们可以将扩展计算表达式与 let! return!?如果是,是否有任何理由不这样做?我问这些问题,因为我没有遇到使用 let!返回!。

  • How does one define or use extended computation expressions without For member (i.e. provide a small complete example)? I don't worry much if they aren't monads any longer, I'm interested in them in developing DSLs.
  • Can we use extended computation expressions with let! and return!? If yes, is there any reason of not doing so? I ask these questions because I haven't encountered any example using let! and return!.

推荐答案

我很高兴您喜欢IL示例。了解表达式如何简化的最佳方法可能是查看规格(虽然有点密集...)。

I'm glad you liked the IL example. The best way to understand how expressions are desugared is probably to look at the spec (though it's a bit dense...).

在这里我们可以看到

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 ,这是因为范围内是否存在变量(例如因为您使用了一些 let ,或者在for循环中,等等),那么您将得到 Yield(v1,v2,...) 0 显然不能用这种方式。请注意,这意味着将多余的 let x = 1 添加到Tomas的 lr 示例中将无法编译,因为<$ c将使用类型为 int 而不是 unit 的参数调用$ c> Yield 。

As to why Yield() is used rather than Zero, it's because if there were variables in scope (e.g. because you used some lets, or were in a for loop, etc.), then you would get Yield (v1,v2,...) but Zero clearly can't be used this way. Note that this means adding a superfluous let x = 1 into Tomas's lr example will fail to compile, because Yield will be called with an argument of type int rather than unit.

还有另一个技巧可以帮助理解计算表达式的编译形式,即(ab)在F#3中使用对计算表达式的自动报价支持。什么都不做的 Quote 成员并使 Run 只是返回其参数:

There's another trick which can help understand the compiled form of computation expressions, which is to (ab)use the auto-quotation support for computation expressions in F# 3. Just define a do-nothing Quote member and make Run just return its argument:

member __.Quote() = ()
member __.Run(q) = q

现在,您的计算表达式将根据其减法形式的引用来求值。调试内容时,这可能非常方便。

Now your computation expression will evaluate to the quotation of its desugared form. This can be pretty handy when debugging things.

这篇关于没有for..in.do的扩展计算表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆