Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# type constructor doesn't act like a function

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)
like image 685
Brian Berns Avatar asked Feb 01 '17 20:02

Brian Berns


3 Answers

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
like image 118
Asti Avatar answered Nov 08 '22 15:11

Asti


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.

like image 2
jpierson Avatar answered Nov 08 '22 15:11

jpierson


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.

like image 1
N_A Avatar answered Nov 08 '22 14:11

N_A