type Identity<'T> = Identity of 'T
type IdentityBuilder() =
member __.Bind (Identity x) (k : 'a -> Identity<'b>) = k x
member __.Return x = Identity x
let identity = new IdentityBuilder()
let three = Identity 3
let four = Identity 4
let twelve =
identity.Bind three <| fun t ->
identity.Bind four <| fun f ->
identity.Return (t * f)
let twelve2 = identity {
let! t = three
let! f = four
return t * f
}
twelve
不会带来任何问题,但是twelve2
会给出
FS0001:该表达式应具有类型 'Identity <'a>',但是这里有类型 ''b *'c'
在let! t = three
行上。
我认为twelve
和twelve2
应该相等...我记错了吗?
答案 0 :(得分:3)
如Szer的注释中所述,您需要对Computation Builder方法使用元组参数。但是,如您的示例所示,将咖喱版本用于流水线通常很方便。因此,我通常要做的是创建一个包含咖喱形式的Computation Builder所需的所有功能的模块,然后在生成器本身中使用它们。这样,根据情况,我可以使用计算表达式语法或流水线语法。
在您的情况下,看起来像这样:
type Identity<'T> = Identity of 'T
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module Identity =
let bind (f: 'T -> Identity<'U>) (Identity x) = f x
let create x = Identity x
type IdentityBuilder() =
member __.Bind (x, f) = Identity.bind f x
member __.Return x = Identity.create x
let identity = new IdentityBuilder()
let three = Identity 3
let four = Identity 4
let twelve =
three |> Identity.bind (fun t ->
four |> Identity.bind (fun f ->
Identity.create (t * f)))
let twelve2 = identity {
let! t = three
let! f = four
return t * f
}
另一种常见做法是为>>=
函数定义一个运算符bind
,以便您可以进一步简化语法:
let (>>=) f x = Identity.bind x f
let twelve3 = three >>= (fun t -> four >>= (fun f -> Identity.create (t * f)))