MIX seqbuilder [CustomOperation]属性方法AND vanilla yield IN单个seq表达式

时间:2015-07-23 16:21:14

标签: f#

此代码运行正常,除非我取消注释自定义seq表达式中的最后一行:

type T (i: int) = 
    member x.i = i
    override x.ToString() =
        sprintf "T is %A " x.i

type TBuilder() =
    member x.Yield (()) = Seq.empty

    [<CustomOperation("test")>]
    member x.Test1 (source : seq<_>, i: int) : seq<T> =
        printfn "Calling Test1 with i= %d" i |> ignore
        seq { yield! source
              yield T(i) }

let t = TBuilder()

let mytest = 
    t {
        test 42
        test 43
//        yield T(44)  // if uncommented, it does not compile
    }

如果取消注释yield T(44)行,我会收到如下编译器错误:

Error   This control construct may only be used if the computation expression builder defines a 'For' method.

我的问题:有没有办法混合

  • 我的[CustomOperation] test (来自方法 Test1 )产生T对象

  • 一个vanilla yield,例如yield T(44)或任何其他seq相关语法

在一个独特的seq表达式中但没有定义任何&#39; For&#39;方法?

参考:Anh-Dung Phan在github上为F#行动的DSL(第7章)。 感谢。

1 个答案:

答案 0 :(得分:1)

简答:不。如果您更改运算符以便它们保留变量绑定(通过MaintainsVariableSpace=trueMaintainsVariableSpaceUsingBind=true属性构造函数的[<CustomOperator>]参数,那么您不会需要For但是您和#39;而是需要Bind

您对意味着的计算表达有何期待?如果你看一下F#规范如何指定计算表达式的翻译,那么任何形式的

bldr {
  op1 x
  op2 y
  yield z
}

会变成类似

的东西
bldr.For(bldr.Op2(bldr.Op1(bldr.Yield(), x), y), fun () -> b.Yield(z))

因此您显然需要For方法,并且您的Yield方法需要做一些不同的事情;至少它需要能够接受任意类型的参数(例如,在上面的例子中,它需要处理类型unit的参数以及值z的任何类型的参数。有)。