3

我试图了解函数类型的方差规则。似乎他们不会将输入和输出视为相同(直到对偶)。考虑这个程序。

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正常?

(*) 对于理论家:我期待阐述者在函数空间类型构造函数的输入和输出位置表现出双重行为。那是错的吗?

4

2 回答 2

4

你有这个:

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

哪个不会编译,向上转换将在输入参数中自动发生,但永远不会在函数的输出中发生。这在规范中,第 14.4.2 节隐式插入使用函数和成员的灵活性。

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

这使得定义限制为子类型的函数的另一个版本成为可能,这是您展示的其他情况。

于 2014-04-10T07:21:56.850 回答
0

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

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

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

于 2014-04-10T09:55:07.467 回答