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

标签 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
}

12 不会引入任何问题,但 twelve2 会带来

FS0001: This expression was expected to have type 'Identity<'a>' but here has type ''b * 'c'

上线让! t = 三

我认为12twelve2应该是等价的......我错了吗?

最佳答案

正如 Szer 的评论中所述,您需要对计算构建器方法使用元组参数。但是,使用柯里化(Currying)版本进行管道传输通常很方便,如您的示例所示。因此,我通常做的是以柯里化(Currying)形式创建一个包含计算构建器所需的所有函数的模块,然后在构建器本身中使用它们。这样我就可以根据场景使用计算表达式语法或管道语法。

就您而言,看起来像这样:

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

关于f# - 计算表达式中的类型推断错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51530646/

相关文章:

f# - Continuation Passing Style 计算表达式

F# 过多调用嵌套计算表达式

database - F# 查询 : find rows with max value in each group

linux - 如何让 XPlot 在 Linux/Mono 上工作?

f# - 计算表达式中的递归函数

f# - 使用 Accord.net 获取数据点到其质心的距离

f# - F# 中 EF C# ToListAsync 的等价物是什么?

f# - 延续单子(monad)中的 StackOverflow

f# - 是否可以使用成员约束创建类型缩写?

f# - F# 如何同时报告语法和语义错误?