1
votes

I've been trying to get rid of explicit arguments in the following F# function:

let mapToSelf (s: seq<'a>): seq<'a> = s |> Seq.map id

This version with an explicit argument s has inferred type seq<'a> -> seq<'a> as expected, and I can use it for mapping over sequences of different types:

let stringSeq = mapToSelf [ "asd"; "qwe" ]
let intSeq = mapToSelf [ 1; 2; 3 ]

So far, so good. Now I would like to remove the explicit function argument s as follows, which I (erroneously?) expect to be equivalent to the first version:

let mapToSelf: (seq<'a> -> seq<'a>) = Seq.map id

Now I get a warning on this line:

let stringSeq = mapToSelf [ "asd"; "qwe" ]
// The construct causes code to be less generic than indicated by the type annotations

And en error on the next line, since the function now has the signature (seq<string> -> seq<string>):

let intSeq = mapToSelf [ 1; 2; 3 ]
// The expression was expected to have type 'string', but here was type 'int'

My question is: why is the generic type signature I specify myself seq<'a> -> seq<'a> gets overridden by a less generic seq<string> -> seq<string>? And is there a way to declare such a function without explicitly specifying the argument?

1

1 Answers

3
votes

You just need to decorate the binding with a generic type:

> let mapToSelf<'T> : seq<'T> -> seq<'T> = Seq.map id;;
val mapToSelf<'T> : (seq<'T> -> seq<'T>)

> mapToSelf [| 1; 2 |];;
val it : seq<int> = seq [1; 2]
> mapToSelf [ "1"; "2" ];;
val it : seq<string> = seq ["1"; "2"]

why is the generic type signature I specify myself seq<'a> -> seq<'a> gets overridden by a less generic seq<string> -> seq<string>?

With no function arguments to type-generalize, the compiler is inferring its type from the first usage.