3. Data types in Haskell
!
!
!
data Person = Person String Int
!
let john = Person “John” 35
let will = Person “William” 28
4. Accessing fields
!
!
let Person name age = john
— pattern match with `let`
putStrLn (“Hello, “ ++ name)
!
personName :: Person -> String
personName (Person name _) = name
!
personAge :: Person -> Int
personAge (Person _ age) = age
5. Changing field data
!
!
!
setPersonName :: Person -> String -> Person
setPersonName (Person _ age) newName =
Person newName age
!
setPersonAge :: Person -> Int -> Person
setPersonAge (Person name _) newAge =
Person name newAge
6. Record Syntax
data Person = Person
{ personName :: String
, personAge :: Int
}
!
let john = Person “John” 35
let will = Person { personName = “William
, personAge = 28
}
!
personName john — => “John”
personAge john — => 35
!
itsABirthday :: Person -> Person
itsABirthday person =
person { personAge = personAge person + 1 }
7. Traversing data
!
data Point = Point { x :: Int, y :: Int }
data Unit = Unit { health :: Int, position :: Point }
!
let pacman = Unit { health = 10, position = Point 0 0 }
let ghost = Unit { health = 1, position = Point 5 3 }
!
moveLeftBy :: Int -> Unit -> Unit
moveLeftBy v unit = let pos = position unit
pos’ = pos { x = x pos - v }
in unit { position = pos’ }
8. Introducing Lenses
!
data Lens s a = Lens { view :: s -> a
, set :: s -> a -> s
}
!
personName :: Lens Person String
personAge :: Lens Person Int
!
view personName john
— => “John”
set personName “John Doe” john
— => Person “John Doe” 35
9. Lens Laws
• Get-Put: view l (set l v s) = v
You get back what you put in!
• Put-Get: set l (view l s) s = s
Putting back what you got doesn’t change anything
• Put-Put: set l v’ (set l v s) = set l v’ s
Setting twice is the same as setting once
10. Operations
!
!
!
view :: Lens s a -> s -> a
!
set :: Lens s a -> a -> s -> s
!
over :: Lens s a -> (a -> a) -> s -> s
11. Composition
— Function composition
(.) :: (b -> c) -> (a -> b) -> (a -> c)
!
!
— Lens composition
lens1 :: Lens a b
lens2 :: Lens b c
!
lens1 . lens2 :: Lens a c
!
— Example
moveLeftBy v unit = over (position.x) (+v) unit
!
unitX :: Lens Unit Int
unitX = position.x
13. Introducing Lenses (2)
!
type Lens s t a b =
forall f. Functor f => (a -> f b) -> s -> f t
!
Allows changing result type
!
type Lens’ s a = Lens s s a a — simple lens
!
Because lenses are just functions,
function composition works without any extra
effort
14. Creating Lenses
data Point = Point { _pointX :: Int
, _pointY :: Int
}
!
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
— Allows creating lens from getter and setter
!
pointX :: Lens’ Point Int
pointX = lens _pointX (p x -> p { _pointX = x })
!
!
{-# LANGUAGE TemplateHaskell #-}
makeLenses ‘’Point
15. Some Lens Operations
(^.) :: Lens s t a b -> s -> a
— Infix version of `view`
— ghost^.position.x
!
(.~) :: Lens s t a b -> b -> s -> t
— Infix version of `set`
— pacman & position.x .~ 10
!
(%~) :: Lens s t a b -> (a -> b) -> s -> t
— Infix version of `over`
— pacman & position.x %~ (+10)
!
(+~) :: Num a => Lens s t a b -> a -> s -> t
— Increment the target of a numerically valued Lens
— pacman & position.x +~ 10
16. MonadState operators
Most operators have a MonadState counterpart, e.g:
!
!
!
(.=) :: MonadState s m => Lens’ s a -> a -> m ()
17. Why changing types?
!
— Example: lenses for tuples
!
_1 :: Lens (a,b) (a',b) a a’
!
_2 :: Lens (a,b) (a,b’) b b’
18. Prisms
They’re like lenses for sum types
data Either e a = Left e | Right a
!
_Left :: Prism’ (Either a b) a
_Right :: Prism’ (Either a b) b
!
!
— go down
preview :: Prism’ s a -> s -> Maybe a
!
— go up
review :: Prism’ s a -> a -> s
19. Prisms
_Left :: Prism’ (Either a b) a
!
>>> preview _Left (Left “hi”)
Just “hi”
!
>>> preview _Left (Right “hi”)
Nothing
!
>>> review _Left “hi”
Left “hi”
!
>>> Left “hi” ^? _Left
Just “hi”
21. Traversals and Folds
Traversable - generalization of traverse, allows you to traverse over
a structure and change out its contents!
!
Foldable - generalization of something Foldable, allows you to extract
multiple results from a container!
!!
traversed :: Traversable f => IndexedTraversal Int (f a) (f b) a b!
folded :: Foldable f => IndexedFold Int (f a) a!
!
(^..) :: s -> Traversal’ s a -> [a]!
(^..) :: s -> Fold s a -> [a]!
!!
>>> sumOf folded [1,2,3,4]!
10!
>>> sumOf (folded.traversed) [[1,2], [3,4]]!
10!
>>> maximumOf (folded.filtered even) [1,4,3,6,7,9,2]!
Just 6
22. Example: Game
{-# LANGUAGE TemplateHaskell #-}!
!
import Control.Lens!
!
data Game = Game!
{ _score :: Int!
, _units :: [Unit]!
, _boss :: Unit!
} deriving (Show)!
!
data Unit = Unit!
{ _health :: Int!
, _position :: Point!
} deriving (Show)!
!
data Point = Point!
{ _x :: Double!
, _y :: Double!
} deriving (Show)!
!
makeLenses ''Game!
makeLenses ''Unit!
makeLenses ''Point