当我尝试使用最后一个参数作为泛型类型来修改函数时,编译器会将泛型类型强制转换为它找到的第一个具体类型,从而丢失其范围内后续调用的泛型属性。例如:
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
最后两行会引发编译错误。
这是预期的行为还是这个错误?如果这是它应该如何工作,有人可以解释为什么?这真让我感到困惑。
答案 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