F# 在单个seq表达式中混合seqbuilder[CustomOperation]属性方法和操作

F# 在单个seq表达式中混合seqbuilder[CustomOperation]属性方法和操作,f#,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表达式中的最后一行:

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
    }
我的问题:有混合的方法吗

  • 我的[CustomOperation]测试(来自方法Test1),它生成T个对象

  • 普通的收益率,例如
    收益率T(44)
    或任何其他与seq相关的语法
在唯一的seq表达式中,但不定义任何“For”方法

参考:Anh Dung Phan-on为F#(第7章)行动中的DSL。
谢谢。

简短回答:不。如果您更改运算符以保留变量绑定(通过
maintansvariablespace=true
maintansvariablespace使用
[]
属性构造函数的Bind=true
参数),那么您将不需要
进行
,而是需要
绑定

你认为你写的计算表达式是什么意思?如果你看看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
具有的任何类型的参数)。

为什么您的收益率成员要接受一个单位?我认为它应该取T值。@Bartek;在引用的参考文献中,产量的定义如下。它返回一个空的seq来初始化seq,然后Test1方法获取到目前为止生成的所有源代码,并添加另一个元素。
bldr.For(bldr.Op2(bldr.Op1(bldr.Yield(), x), y), fun () -> b.Yield(z))