I'm trying to understand the variance rules for function types. It seems they don't treat input and output the same (up to duality). Consider this program.
let mk1 s = s |> Seq.iter (fun _ -> ())
// val mk1 : s:seq<'a> -> unit
let mk2 = mk1 : list<int> -> unit // Ok.
let mk3 () = [1]
// val mk3 : unit -> int list
let mk4 = mk3 : unit -> seq<int> // Type mismatch.
This is the error:
Type mismatch. Expecting a
unit -> seq<int>
but given a
unit -> int list
The type 'seq<int>' does not match the type 'int list'
It's my understanding that seq<int>
is an interface type, one which int list
implements, so I was expecting this cast to go through(*).
Two questions:
- Why doesn't it?
- Why is the cast producing
mk2
ok?
(*) For theorists: I was expecting the elaborator to exhibit dual behaviour on the input and output positions of the function space type constructor. Is that wrong?