函数类型的变化wrt。接口

时间:2014-04-10 06:48:50

标签: f# generic-variance

我试图理解函数类型的方差规则。似乎他们不会对输入和输出进行相同的处理(达到二元性)。考虑这个计划。

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. 

这是错误:

Type mismatch. Expecting a
    unit -> seq<int>    
but given a
    unit -> int list    
The type 'seq<int>' does not match the type 'int list'

我的理解是seq<int>是一个接口类型,int list实现的接口类型,所以我期待这个演员经历(*)。

两个问题:

  1. 为什么不呢?
  2. 为什么演员表生成mk2好吗?

  3. (*)对于理论家:我期望elaborator在函数空间类型构造函数的输入和输出位置上表现出双重行为。这是错的吗?

2 个答案:

答案 0 :(得分:4)

你有这个:

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

哪个不会编译,上传将自动发生在输入参数中,但从不在函数的输出中。这是spec第14.4.2节对函数和成员使用的灵活性的隐式插入。

这意味着推断类型在参数位置包含未密封类型的F#函数可以在调用时传递子类型,而不需要显式的向上转换。

这样就可以定义另一个限制为子类型的函数版本,这是你要显示的其他情况。

答案 1 :(得分:0)

有趣的是,您可以使用灵活类型来定义mk4,如下所示:

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

它会编译但会自动将mk4的类型提升到unit -> int list