Is there a reason why I can use a generic function with different type arguments when I pass it as a local value but not when passed as parameter? For example:
As rkhayrov mentioned in a comment, type inference is impossible when you can have higher ranked types. In your example, you have
let g f (x,y) = (f x, f y)
Here are two possible types for g
which are incompatible (written in a sort of hybrid F#/Haskell syntax):
Given the first type, we could call g (fun x -> 1) ("test", true)
and get (1,1)
. Given the second type, we could call g id ("test", true)
and get ("test", true)
. Neither type is more general than the other.
If you want to use higher ranked types in F#, you can, but you have to be explicit and use an intermediate nominal type. Here's one way to encode each of the possibilities above:
module Example1 =
type ConvertAll<'b> =
abstract Invoke<'a> : 'a -> 'b
let g (f:ConvertAll<'b>) (x,y) = (f.Invoke x, f.Invoke y)
//usage
let pair = g { new ConvertAll with member __.Invoke(x) = 1 } ("test", true)
module Example2 =
type PassThrough =
abstract Invoke<'a> : 'a -> 'a
let g (f:PassThrough) (x,y) = (f.Invoke x, f.Invoke y)
//usage
let pair = g { new PassThrough with member __.Invoke(x) = x } ("test", true)