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


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

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

正如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)))

相关内容

  • 没有找到相关文章