f#currying函数失去泛型类型?

时间:2013-11-06 00:28:06

标签: generics f# type-inference

当我尝试使用最后一个参数作为泛型类型来修改函数时,编译器会将泛型类型强制转换为它找到的第一个具体类型,从而丢失其范围内后续调用的泛型属性。例如:

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

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

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

最后两行会引发编译错误。

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

1 个答案:

答案 0 :(得分:3)

所以这是一个经典的价值限制问题。如果你只是做这段代码就更明显了:

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

这将产生以下错误:

  

错误FS0030:值限制。已推断值'fooWithA'具有泛型类型       val fooWithA:('_a - > unit)
  要么将'fooWithA'的参数显式化,要么如果你不打算将它作为泛型,那么添加一个类型注释。

问题是fooWithA不是一个正确的函数,因此不允许使用泛型类型。

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

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

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

所有这一切的最简单的解决方案是始终使用像这样的函数

let fooWithA a = foo "hello" a
相关问题