Record Syntax, Lenses and Prisms: Part 3 - Prisms
Prisms
So what are prisms?
Prisms are like lenses just for sum types … - the most memorable sentence, but I don’t think very helpful at first glance.
So let us start with defining a sum type.
> data Town = Prague | Vienna | Kingston | London | Hipsterhausen deriving (Show, Eq)
> data Pirate = Captain { _attributes :: Human, _ship :: String}
> | FirstMate { _attributes :: Human, _shanty :: String}
> | Marauder { _attributes :: Human, _hometown :: Town}
> makeLenses ''Human
> makeLenses ''Body
> makeLenses ''PiratePirate is a sum type - with different records in each constructor.
A tangent on sums and products
Sums
Why is the above called a sum type, just let us calculate the number of options we have in a sum type:
If I have a variable x :: Sum it has exactly three values it can be
x = Onex = Twox = Three
so the sum of the number of constructors is the solution of how many options x can be.
Product
So how come product types to their names - you might already guess it.
For a variable y :: Product we find y can be |Sum|×|Sum| many possible values:
y = P One Oney = P One Twoy = P One Threey = P Two Oney = P Two Twoy = P Two Threey = P Three Oney = P Three Twoy = P Three Three
So can anybody find what exponential types are?
The answer is functions
So the functions from Two -> THREE have exactly |Two|^|THREE| many elements.
one,two,three,four,five,six,seven,eight :: Two -> THREE
one One = ONE
one Two = ONE
two One = TWO
two Two = TWO
three One = THREE
three Two = THREE
four One = ONE
four Two = TWO
five One = ONE
five Two = THREE
six One = TWO
six Two = THREE
seven One = THREE
seven Two = ONE
eight One = THREE
eight Two = TWOBack to Prisms
The problem with lenses is that cpt some getters don’t make sense. For datatypes that have a special elements, so called monoids like String with "" we get special getters, but for Town for example …
Prelude > cpt^.shanty
""
Prelude > cpt^.hometown
...
error message complaining about Town not being a monoid
...So an easy way to get special elements is combining it with Maybe. And that’s what prisms are - getters with Maybe-values instead of errors.
So how do we get them - again as with prisms we (have to) build them with template haskell magic using
This magic words create “Constructors” _Captain, _FirstMate and _Marauder and the lens library provides functions preview, review and ^?.
Now what are those functions doing - they select one branch in a sum type.
Prelude > preview _Captain cpt
Just (Attributes {...},"SS Sea Serpent")
Prelude > preview _Captain mrd
NothingBut there is also an infix shortcut for preview - (^?) so we could have written the above cpt^._Captain or use it with accessor-like functions as hometown,ship,shanty or attributes.
Prelude > cpt^?hometown
Nothing
Prelude > cpt^?ship
Just "SS Sea Serpent"
Prelude > mrd^?hometown
Just HipsterhausenSo what about review?
The review function can create new things from the results of preview, well not exactly but almost and with use of (<$>) from Control.Applicative we can make them work together
Prelude> :t preview _Captain cpt
preview _Captain cpt :: Maybe (Human, String)
Prelude> let Just x = preview _Captain cpt
Prelude> :t review _Captain x
review _Captain x :: Pirate
Prelude> :t review _Captain <$> preview _Captain cpt
review _Captain <$> preview _Captain cpt :: Maybe Pirate
Prelude> review _Captain <$> preview _Captain cpt
Just Captain {Attributes {...},"SS Sea Serpent"}
Prelude> review _Captain <$> preview _Captain mrd
Nothing
Prelude> review _Captain <$> preview _Marauder mrd
... Error ... -- Captain needs String (ship name) where Marauder has a Town as
a second argumentSo Prisms do not fix everything - but provide a safety layer for simple accessing stuff and sometimes for generating stuff as well.
So thats all I know about Lenses and Prisms - for understanding the type signatures - I still do not feel confident to present about.
