此代码运行正常,除非我取消注释自定义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.
我的问题:有没有办法混合
带
yield T(44)
或任何其他seq相关语法在一个独特的seq表达式中但没有定义任何&#39; For&#39;方法?
参考:Anh-Dung Phan在github上为F#行动的DSL(第7章)。 感谢。
答案 0 :(得分:1)
简答:不。如果您更改运算符以便它们保留变量绑定(通过MaintainsVariableSpace=true
或MaintainsVariableSpaceUsingBind=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
的任何类型的参数。有)。