Joking around constructors
Where we learn how to put data into our custom types.
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?… 😩