Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

lists of discriminated unions in fsharp

Can anybody explain why following 2 let statements don't work?

 type Rank =
 | Two
 | Three
 | Four
 | Five
 | Six
 | Seven
 | Eight
 | Nine
 | Ten

 type Face =
 | Jack
 | Queen
 | King
 | Ace

 type Suit =
 | Diamonds
 | Clubs
 | Hearts
 | Spades

 type Card =
 | RankCard of Rank * Suit
 | FaceCard of Face * Suit


 let deck : Card = [ (Two, Diamonds); (Jack, Hearts) ]

This expression was expected to have type Card but here has type 'a list

and this let gives

 let deck : Card list = [ (Two, Diamonds); (Jack, Hearts) ]

expression was expected to have type Card but here has type 'a * 'b

like image 569
user1120753 Avatar asked Dec 07 '22 16:12

user1120753


2 Answers

F# is a type-safe language. So the first expression is wrong since Card and 'a list are incompatible. The second expression is also incorrect because your annotation requires list elements in Card type but you provided tuples instead.

Moreover, (Two, Diamonds) and (Jack, Hearts) are not even legal to use in the same list. The former is a tuple of Rank * Suit and the latter is a tuple of Face * Suit.

Your intention is creating two values of type Card; you have to provide appropriate constructors based on different union cases of Card:

let c1 = RankCard (Two, Diamonds)  // c1: Card
let c2 = FaceCard (Jack, Hearts) // c2: Card

Now you can use c1 and c2 in the same list deck, and F# type checker will automatically infer deck to have the type of Card list:

let deck = [c1; c2] // deck: Card list

Alternatively, you have a list as follows:

let deck = [RankCard (Two, Diamonds); FaceCard (Jack, Hearts)]
like image 133
pad Avatar answered Dec 17 '22 12:12

pad


You need to use the RankCard or FaceCard constructor -- otherwise F# thinks you've just given it a normal list of tuples.

Alternatively, why not let F# infer the types itself?

like image 31
Matt Fenwick Avatar answered Dec 17 '22 12:12

Matt Fenwick