F#在Math.Max上的类型推断

时间:2014-03-06 12:08:13

标签: .net f#

如果编译器推断出输入参数的类型,为什么编译器不会选择正确版本的重载方法。

在这个例子中,为什么它不能选择正确的Math.Max,以便在被比较的元素上正确推断类型时使用:

let listMax = 
    List.map2 (fun l r -> Math.Max(l,r)) [2;4] [5;3]       //compile error 
let listMax2 = 
    List.map2 (fun (l:int) r -> Math.Max(l,r)) [2;4] [5;3] //no compile error    

当然,在这种情况下你可以使用max函数,但是还有很多其他方法没有本机等价物。

2 个答案:

答案 0 :(得分:7)

正如@Gos正确指出的那样,在这种情况下使用管道运算符会有所帮助。原因是类型推断从左到右工作 - 因此,如果使用管道运算符,它知道其中一个输入是整数列表,并且基于此,它选择{{1}的正确重载}。

编译器通常需要在重载解析时或者想要调用对象上的成员时知道类型(例如,如果你想在map函数中执行Math.Max) - 因为在这种情况下,它需要知道究竟是什么类型。

F#还定义了自己的基本数学函数版本,这些函数在类型推断方面效果更好。因此,您可以将l.Foo()替换为Math.Max函数(您也可以直接将其传递给max):

map2

这更好用,因为F#不需要执行重载解析(函数不会重载)。它只是跟踪一个特殊的泛型约束,它将在以后得到满足和解决。

答案 1 :(得分:1)

我无法告诉你原因,但我发现管道运营商经常帮助输入推理:

let listMax = 
    [5;3] |> List.map2 (fun l r -> Math.Max(l,r)) [2;4]