如果我定义这样的类型:
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)
答案 0 :(得分:3)
这是一个协方差问题。
类型构造函数Items
是seq<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
答案 1 :(得分:2)
这更像是一个猜测而不是答案,但我怀疑这个问题可能与C#中的类似行为有关,因为构造函数不能有类型参数。默认情况下,我理解F#函数是完全通用的,只能通过类型注释和推理变得专业化。如果构造函数无法具有类型参数,那么通常会将其引入CLR或.NET,那么它可以解释为什么F#类型构造函数可能无法按照默认行为执行与函数相同的通用操作。
答案 2 :(得分:1)
如果您将代码更改为:
> 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>
问题变得更加明显。几乎相同的类型签名但仍然是同样的问题。我很确定这是使用构造函数作为第一类函数的错误。