Reputation: 751
Why won't the compiler pick the correct version of an overloaded method if it has inferred the types of the input parameters.
In this example why can't it pick the correct Math.Max to use when the type has correctly inferred on the elements being compared:
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
Of course you can just use the max function in this case, but there are plenty of other methods that don't have a native equivalent.
Upvotes: 2
Views: 990
Reputation: 243041
As @Gos correctly points out, using the pipeline operator helps in this case. The reason is that the type inference works from left to right - so, if you use the pipeline operator, it knows that one of the inputs is a list of integers and, based on that, it picks the right overload of Math.Max
.
The compiler generally needs to know the type when it does overload resolution or when you want to invoke a member on a object (e.g. if you wanted to do l.Foo()
inside the map function) - because in this case, it needs to know what exactly the type is.
F# also defines its own versions of basic math functions which work better with type inference. So you can replace Math.Max
with the max
functions (which you can also nicely pass directly to map2
):
List.map2 max [2;4] [5;3]
This works better, because F# does not need to perform overload resolution (the function is not overloaded). It just keeps track of a special generic constraint that is satisfied and resolved later.
Upvotes: 7
Reputation: 2344
I can't tell you why but I found that the pipeline operator often helps type inference:
let listMax =
[5;3] |> List.map2 (fun l r -> Math.Max(l,r)) [2;4]
Upvotes: 1