【问题标题】:f# currying function loses generic type? [duplicate]f# currying 函数丢失泛型类型? [复制]
【发布时间】:2013-11-17 02:01:40
【问题描述】:

当我尝试将带有最后一个参数的函数作为泛型类型进行柯里化时,编译器会将泛型类型强制转换为它找到的第一个具体类型,从而在范围内的后续调用中失去其泛型属性。示例:

type Bar =
    | String
    | Integer
    | Boolean

let foo (a: String)(b: 'm) =
    printfn "%A - %A" a b

let foobar (a: String)(bar: Bar) =
    let fooWithA= foo a
    match bar with
    | String -> fooWithA "String"
    | Integer -> fooWithA 42
    | Boolean -> fooWithA true

最后两行给了我一个编译器错误,说明该函数需要一个字符串。但是,如果我用辅助类包装函数,我可以让它像这样工作:

type FooHelper(a:String) =
    member this.foo (b: 'm) =
        printfn "%A - %A" a b

let foobar (a: String)(bar: Bar) =
    let fooHelperWithA= FooHelper a
    match bar with
    | String -> fooHelperWithA.foo "String"
    | Integer -> fooHelperWithA.foo 42
    | Boolean -> fooHelperWithA.foo true

这不会给我一个编译器错误。然后,如果我直接尝试使用该函数,我会再次遇到编译错误:

let foobar (a: String)(bar: Bar) =
    let fooHelperWithA= FooHelper(a).foo
    match bar with
    | String -> fooHelperWithA "String"
    | Integer -> fooHelperWithA 42
    | Boolean -> fooHelperWithA true

最后两行抛出编译错误。

这是预期的行为还是错误?如果这是它应该如何工作,有人可以解释为什么吗?这真的让我很困惑。

【问题讨论】:

标签: generics f# type-inference


【解决方案1】:

所以这是一个经典的值限制问题。如果您只是执行此代码块,则更明显:

let foo (a: String)(b: 'm) =
    printfn "%A - %A" a b 
let fooWithA= foo  "hello"

这将给出以下错误:

错误 FS0030:值限制。值 'fooWithA' 已被推断为具有泛型类型 val fooWithA : ('_a -> 单位)
将 'fooWithA' 的参数设为显式,或者,如果您不希望它是通用的,请添加类型注释。

问题在于fooWithA 不是一个合适的函数,因此不允许它具有泛型类型。

所以在第一个例子中,编译器看到你首先用一个字符串调用它,所以它进行了这种特殊化,然后对于整数和布尔情况失败。

在第二个示例中,您隐式创建了一个可以通用的函数,所以一切都很好。

在第三个示例中,您遇到与第一个示例相同的问题,您将函数绑定到一个值,因此它不能是通用的。

解决这一切的最简单方法是始终使用这样的函数

let fooWithA a = foo "hello" a

【讨论】:

  • 我明白了...我对 F# 有点陌生,当听说 currying 时,我认为它们与某些参数设置为默认值的函数完全一样。猜我错了。你的简单解决方案对我有用:)
猜你喜欢
  • 1970-01-01
  • 2019-05-26
  • 1970-01-01
  • 1970-01-01
  • 2016-06-11
  • 1970-01-01
  • 2020-02-05
  • 2012-12-19
  • 1970-01-01
相关资源
最近更新 更多