计算表达式中的类型推断错误

时间:2018-07-26 03:39:16

标签: f# computation-expression

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行上。

我认为twelvetwelve2应该相等...我记错了吗?

1 个答案:

答案 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)))