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:此表达式的类型应为'标识<'a> '但这里有类型'b*'c'
在线let! t = three
上。
我认为twelve
和twelve2
应该相等。。。我错了吗?
正如Szer在评论中所指出的,您需要为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)))