Super-mega-duper-straight but no flush.

Joking around constructors

Where we learn how to put data into our custom types.

Michel Belleville
Published in
3 min readDec 27, 2018

--

me> Wat?

wat> What, wat?

me> It’s about types again…

wat> Isn’t it always about types? What’s on your mind?

me> Last time we talked about how to make new types that are specific to our data, and I’ve tried to use it to model playing cards. I wanted to be able to add the joker but I’m hitting a roadblock.

wat> Let’s see…

type Suit = Clubs | Hearts | Diamonds | Spadestype Rank = Ace | Two | Three | Four | Five | Six | Seven | Height | Nine | Ten | Jack | Queen | Kingtype alias Card =
{ suit : Suit
, rank : Rank
}

wat> …Why sssso ssssseriousssss? 😈

me> The way this works, I’ll be forced to add a JokerSuit and a JokerRank respectively to Suit and Rank and that doesn’t feel right.

wat> Yes, you could end up with a Joker of Hearts or a Queen of Joker. Let me suggest using a specific type for your Card instead of an alias then…

me> …and spend the afternoon writing all 55 Suit and Rank combinations? I pass.

wat> Not quite:

type Suit = Clubs | Hearts | Diamonds | Spadestype Rank = Ace | Two | Three | Four | Five | Six | Seven | Height | Nine | Ten | Jack | Queen | Kingtype Card
= Standard Suit Rank
| Joker

me> So… it’s either Standard with a Suit and a Rank, or it’s Joker?

wat> Yep. When you define a new type constructor, you can add values inside each.

me> So, when I create a Standard card value, I will have to give it a Suit and a Rank to make it complete, right? Like this?

aceOfClubs = Standard Club Ace

wat> Indeed. Creating a Joker on the other hand, is as simple as:

clown = Joker

me> Ok. But how can I know which Suit and Rank a card is (if any) when it’s wrapped into a Card value?

wat> Pattern matching. Say I want to have a String designation of a Card, any Card:

-- I'll let you try and implement those two as an exercise,
-- and not at all because I'm a lazy ducky ;)
rankToString : Rank -> String
...
suitToString : Suit -> String
...
cardToString : Card -> String
cardToString card =
case card of
Standard suit rank ->
rankToString rank ++ " of " ++ suitToString suit
Joker ->
"Joker :}"

me> So… in the first branch, suit and rank are like variables in JavaScript or another imperative language, right? They’ll hold the values Standard value is holding inside…

wat> Yep. The Joker holds nothing, so there is no “variable” there to match.

me> What are those constructors exactly?

wat> They’re either values or functions that will produce a value once you give them their parameters. See the type of our Joker card constructor, and compare to Standard:

Joker : Card
Standard : Suit -> Rank -> Card

me> Ooooh, I see! So, the constructor is a function that takes a Suit and a Rank and will produce a Card, while Joker is already a Card value on its own.

wat> Exactly. Constructors are functions (or straightforward values) the language gives you free of charge when you define types by yourself. And there’s plenty of fun things to do with them…

me> Can we do them later?… 😩

wat> Sure. I’ll stay put (on your desk). 😉

--

--