【问题标题】:Type inference error in computation expression计算表达式中的类型推断错误
【发布时间】:2018-07-26 20:19:44
【问题描述】:
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' 但这里有类型 ''b * 'c'

上线let! t = three

我认为twelvetwelve2 应该是等价的……我弄错了吗?

【问题讨论】:

  • Bind 对于 CE 构建器必须具有元组形式,而不是柯里化形式。改成Bind (x, k)

标签: f# computation-expression


【解决方案1】:

正如 Szer 的评论中所指出的,您需要对 Computation Builder 方法使用元组参数。但是,如您的示例中那样,使用 curried 版本进行流水线操作通常很方便。因此,我通常做的是创建一个模块,其中包含计算生成器所需的所有功能,以柯里化形式,然后在生成器本身中使用它们。这样我可以根据场景使用计算表达式语法或流水线语法。

在你的情况下,这看起来像这样:

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 函数定义一个运算符&gt;&gt;=,以便您可以进一步简化语法:

let (>>=) f x = Identity.bind x f

let twelve3 = three >>= (fun t -> four >>= (fun f -> Identity.create (t * f)))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-20
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-11
    • 2012-12-29
    • 2014-07-27
    相关资源
    最近更新 更多