f# - 不带 for..in..do 的扩展计算表达式

标签 f# dsl computation-expression query-expressions

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

阅读时 extended computation expressions ,我遇到了@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! 中使用扩展计算表达式吗?和 return! ?如果是,是否有任何理由不这样做?我问这些问题是因为我没有遇到任何使用 let! 的例子。和 return! .
  • 最佳答案

    很高兴您喜欢 IL 示例。了解表达式如何脱糖的最好方法可能是查看 spec (虽然它有点密集......)。

    在那里我们可以看到类似的东西

    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,...)但是 Zero显然不能这样使用。请注意,这意味着添加一个多余的 let x = 1进入托马斯的lr示例将无法编译,因为 Yield将使用 int 类型的参数调用而不是 unit .

    还有一个技巧可以帮助理解计算表达式的编译形式,即(ab)使用 F# 3 中计算表达式的自动引用支持。只需定义一个什么都不做 Quote成员(member)和制作 Run只需返回其参数:
    member __.Quote() = ()
    member __.Run(q) = q
    

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

    关于f# - 不带 for..in..do 的扩展计算表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14110532/

    相关文章:

    algorithm - 是否存在进行波前迭代器的有效方法? (与物理无关。)

    msbuild - 在 Vs2013 中使用 FsLex/Yacc

    python - 使用 DSL 的 pyparsing 评估嵌套变量

    f# - 为什么这个 F# 计算表达式会给出警告?

    f# - 如何在计算表达式中使用自定义操作从构建器访问值

    f# - 计算表达式是面向方面编程的替代方法吗?

    f# - 没有抽象成员的抽象类的对象表达式

    f# - try 语句中的 with/finally block 为空

    java - XText:交叉引用找不到引用

    c# - 领域特定语言 (DSL) 和领域驱动设计 (DDD)