F# 类型构造函数不像函数



如果我定义这样的类型:

type Foo = Items of seq<int>

我可以创建一个Foo,如下所示:

Items [1;2;3]

但是,以下方法不起作用:

[1;2;3] |> Items

错误消息是:

Type mismatch. Expecting a
    int list -> 'a    
but given a
    seq<int> -> Foo

编译器不应该能够将int list转换为seq<int>吗?如果 Items 构造函数是一个普通函数,我可以以任何一种方式调用它:

let length ints = Seq.length ints
printfn "%A" (length [1;2;3])
printfn "%A" ([1;2;3] |> length)

这是一个协方差问题。类型构造函数Itemsseq<int> -> Items的,但被赋予了一个List<int>,你必须显式地向上转换,因为F#不执行自动子类型转换。

type Foo = Items of int list
[1;2;3] |> Items //compiles

或使用相关模块

type Foo = Items of int seq
[1;2;3] |> Seq.ofList |> Items //compiles

这与其说是答案,不如说是猜测,但我怀疑该问题可能与 C# 中的类似行为有关,因为构造函数不能具有类型参数。默认情况下,我的理解是 F# 函数是完全通用的,只有通过类型注释和推理才能变得专用。如果构造函数无法具有类型参数是一般烘焙到 CLR 或 .NET 中的原因,那么它可能会解释为什么 F# 类型构造函数可能无法遵循与函数相同的默认行为。

如果您将代码更改为如下所示:

> type Foo = Items of seq<int>;;
> Items;;
val it : arg0:seq<int> -> Foo = <fun:clo@18-5>
> let length (ints: int seq) = Items ints;;
> length;;
val it : (seq<int> -> Foo) = <fun:it@20-3>

这个问题变得更加明显。 几乎相同的类型签名,但仍然是相同的问题。 我很确定这是使用构造函数作为一等函数的错误。

相关内容

  • 没有找到相关文章

最新更新