If I define a type like this:
type Foo = Items of seq<int>
I can create a Foo
as follows:
Items [1;2;3]
However, the following doesn't work:
[1;2;3] |> Items
The error message is:
Type mismatch. Expecting a
int list -> 'a
but given a
seq<int> -> Foo
Shouldn't the compiler be able to convert an int list
into a seq<int>
? If the Items
constructor was a normal function, I could invoke it either way:
let length ints = Seq.length ints
printfn "%A" (length [1;2;3])
printfn "%A" ([1;2;3] |> length)
This is a covariance issue.
The type constructor function Items
is seq<int> -> Items
, but is given a List<int>
, which you will have to explicitly upcast as F# does not do automatic subtype conversion.
type Foo = Items of int list
[1;2;3] |> Items //compiles
or use the relevant Module
type Foo = Items of int seq
[1;2;3] |> Seq.ofList |> Items //compiles
This is more of a guess than an answer but I suspect that the issue may be related to similar behavior in C# in that constructors cannot have type parameters. By default it is my understanding that F# functions are completely generic and only become specialized through type annotations and inference. If the inability for constructors to have type parameters is something that is baked into the CLR or .NET in general then it may explain why F# type constructors may not be able to follow this same generic by default behavior as is done for functions.
If you change your code to be like this:
> 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>
The issue becomes even more apparent. Nearly identical type signature but still the same problem. I'm pretty sure this is a bug with using constructors as first-class functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With