3

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:

  1. Why doesn't it?
  2. 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?

Søren Debois
  • 5,598
  • 26
  • 48

2 Answers2

4

You have this:

let mk4 = mk3  : unit -> seq<int>

Which will not compile, the up-cast will happen automatically in the input parameter but never in the output of the function. This is in the spec, section 14.4.2 Implicit Insertion of Flexibility for Uses of Functions and Members.

This means that F# functions whose inferred type includes an unsealed type in argument position may be passed subtypes when called, without the need for explicit upcasts.

This makes possible to define another version of the function which is restricted to a subtype, which are the other cases you're showing.

Gus
  • 25,839
  • 2
  • 51
  • 76
0

Interestingly, you can use flexible types to define mk4 as follows:

let mk4 = mk3 : unit -> #seq<int>

It compiles but automatically lifts the type of mk4 up to unit -> int list

Andrew Khmylov
  • 732
  • 5
  • 18
  • Yes, cause the Type Inference is smart enough to figure out the only subtype of seq that will return is list. It's a typical case when the type annotation is more generic than the one inferred, a warning is displayed in these cases. – Gus Apr 10 '14 at 11:03