Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining discriminated unions with record types

Tags:

f#

I'm trying to get my head around discriminated unions and record types; specifically how to combine them for maximum readability. Here's an example - say a sports team can either have points (both league points and goal difference), or it can be suspended from the league in which case it has no points or goal difference. Here's how I tried to express that:

type Points = { LeaguePoints : int; GoalDifference : int }

type TeamState = 
    | CurrentPoints of Points
    | Suspended

type Team = { Name : string; State : TeamState }

let points = { LeaguePoints = 20; GoalDifference = 3 }

let portsmouth = { Name = "Portsmouth"; State = points }

The problem comes at the end of the last line, where I say 'State = points'. I get 'Expression was expected to have type TeamState but here has type Points'. How do I get around that?

like image 252
Kit Avatar asked Apr 12 '12 15:04

Kit


2 Answers

To add some details to pad's answer, the reason why your initial version did not work is that the type of value assigned to State should be a discriminated union value of type TeamState. In your expression:

let portsmouth = { Name = "Portsmouth"; State = points }

...the type of points is Points. In the version posted by pad, the expression CurrentPoints points uses a constructor of TeamState to create a discriminated union value representing CurrentPoints. The other option that the union gives you is Suspended, which can be used like this:

let portsmouth = { Name = "Portsmouth"; State = CurrentPoints points }
let portsmouth = { Name = "Portsmouth"; State = Suspended }

If you did not use the name of the constructor, then it is not clear how you'd construct a suspended team!

Finally, you can also write everything on just a single line, but that's not as readable:

let portsmouth = 
  { Name = "Portsmouth"
    State = CurrentPoints { LeaguePoints = 20; GoalDifference = 3 } }
like image 76
Tomas Petricek Avatar answered Feb 19 '23 07:02

Tomas Petricek


let portsmouth = { Name = "Portsmouth"; State = CurrentPoints points }
like image 36
pad Avatar answered Feb 19 '23 05:02

pad