30
Lenses Maxim Kulkin

λ | Lenses

  • Upload
    open-it

  • View
    228

  • Download
    1

Embed Size (px)

DESCRIPTION

Discussion: Lenses Author: Maxim Kulkin Agenda: Why do you need to use lenses? Types of lenses.

Citation preview

Page 1: λ | Lenses

LensesMaxim Kulkin

Page 2: λ | Lenses

Why Lenses?

Page 3: λ | Lenses

Data types in Haskell!!!data Person = Person String Int!let john = Person “John” 35let will = Person “William” 28

Page 4: λ | Lenses

Accessing fields!!let Person name age = john — pattern match with `let`putStrLn (“Hello, “ ++ name)!personName :: Person -> StringpersonName (Person name _) = name!personAge :: Person -> IntpersonAge (Person _ age) = age

Page 5: λ | Lenses

Changing field data!!!setPersonName :: Person -> String -> PersonsetPersonName (Person _ age) newName = Person newName age!setPersonAge :: Person -> Int -> PersonsetPersonAge (Person name _) newAge = Person name newAge

Page 6: λ | Lenses

Record Syntaxdata Person = Person { personName :: String , personAge :: Int }!let john = Person “John” 35let will = Person { personName = “William , personAge = 28 }!personName john — => “John”personAge john — => 35!itsABirthday :: Person -> PersonitsABirthday person = person { personAge = personAge person + 1 }

Page 7: λ | Lenses

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 -> UnitmoveLeftBy v unit = let pos = position unit pos’ = pos { x = x pos - v } in unit { position = pos’ }

Page 8: λ | Lenses

Introducing Lenses!data Lens s a = Lens { view :: s -> a , set :: s -> a -> s }!personName :: Lens Person StringpersonAge :: Lens Person Int!view personName john — => “John”set personName “John Doe” john — => Person “John Doe” 35

Page 9: λ | Lenses

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

Page 10: λ | Lenses

Operations!!!

view :: Lens s a -> s -> a!set :: Lens s a -> a -> s -> s!over :: Lens s a -> (a -> a) -> s -> s

Page 11: λ | Lenses

Composition— Function composition(.) :: (b -> c) -> (a -> b) -> (a -> c)!!— Lens compositionlens1 :: Lens a blens2 :: Lens b c!lens1 . lens2 :: Lens a c!— ExamplemoveLeftBy v unit = over (position.x) (+v) unit!unitX :: Lens Unit IntunitX = position.x

Page 12: λ | Lenses

Those are naive lenses

Page 13: λ | Lenses

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 extraeffort

Page 14: λ | Lenses

Creating Lensesdata 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 IntpointX = lens _pointX (\p x -> p { _pointX = x })!!{-# LANGUAGE TemplateHaskell #-}makeLenses ‘’Point

Page 15: λ | Lenses

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

Page 16: λ | Lenses

MonadState operatorsMost operators have a MonadState counterpart, e.g:!!!(.=) :: MonadState s m => Lens’ s a -> a -> m ()

Page 17: λ | Lenses

Why changing types?!— Example: lenses for tuples!

_1 :: Lens (a,b) (a',b) a a’!_2 :: Lens (a,b) (a,b’) b b’

Page 18: λ | Lenses

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 downpreview :: Prism’ s a -> s -> Maybe a!— go upreview :: Prism’ s a -> a -> s

Page 19: λ | Lenses

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” ^? _LeftJust “hi”

Page 20: λ | Lenses

Prism examples_Cons :: Prism' [a] (a, [a])!>>> preview _Cons []Nothing!>>> preview _Cons [1,2,3]Just (1, [2,3])!_Nil :: Prism' [a] ()!>>> preview _Nil []Just ()!>>> preview _Nil [1,2,3]Nothing

_ParseTrue :: Prism' String Bool_ParseFalse :: Prism' String Bool!>>> preview _ParseTrue "True"Just True!>>> preview _ParseFalse "True"Nothing!>>> review _ParseTrue True"True"

Page 21: λ | Lenses

Traversals and FoldsTraversable - 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

Page 22: λ | Lenses

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

Page 23: λ | Lenses

Example: GameinitialState :: Game!initialState = Game! { _score = 0! , _units =! [ Unit! { _health = 10! , _position = Point { _x = 3.5, _y = 7.0 }! }! , Unit! { _health = 15! , _position = Point { _x = 1.0, _y = 1.0 }! }! , Unit! { _health = 8! , _position = Point { _x = 0.0, _y = 2.1 }! }! ]! , _boss = Unit! { _health = 100! , _position = Point { _x = 0.0, _y = 0.0 }! }! }

Page 24: λ | Lenses

Example: Gameimport Control.Monad.Trans.Class!import Control.Monad.Trans.State!!strike :: StateT Game IO ()!strike = do! lift $ putStrLn "*shink*"! boss.health -= 10!!!!>>> newState <- execStateT strike initialState !*shink*!!>>> newState^.boss.health!90

Page 25: λ | Lenses

Example: Gameunits :: Lens' Game [Unit]!units.traversed :: Traversal' Game Unit!units.traversed.health :: Traversal' Game Int!!!!partyHP :: Traversal' Game Int!partyHP = units.traversed.health!!fireBreath :: StateT Game IO ()!fireBreath = do! lift $ putStrLn "*rawr*"! partyHP -= 3!!!>>> initialState^..partyHP![10,15,8]!!>>> newState <- execStateT fireBreath initialState !!>>> newState^..partyHP![7,12,5]

Page 26: λ | Lenses

Example: Gamearound :: Point -> Double -> Traversal' Unit Unit!around center radius = filtered (\unit ->! (unit^.position.x - center^.x)^2! + (unit^.position.y - center^.y)^2! < radius^2 )!!fireBreath :: Point -> StateT Game IO ()!fireBreath target = do! lift $ putStrLn "*rawr*"! units.traversed.(around target 1.0).health -= 3

Page 27: λ | Lenses

Example: GamepartyLoc :: Traversal' Game Point!partyLoc = units.traversed.position!!retreat :: StateT Game IO ()!retreat = do! lift $ putStrLn "Retreat!"! zoom partyLoc $ do! x += 10! y += 10

Page 28: λ | Lenses

Example: Gamebattle :: StateT Game IO ()!battle = do! -- Charge!! forM_ ["Take that!", "and that!", "and that!"] $ \taunt -> do! lift $ putStrLn taunt! strike!! -- The dragon awakes!! fireBreath (Point 0.5 1.5)! ! replicateM_ 3 $ do! -- The better part of valor! retreat!! -- Boss chases them! zoom (boss.position) $ do! x += 10! y += 10

>>> execStateT battle initialState !Take that!!*shink*!and that!!*shink*!and that!!*shink*!*rawr*!Retreat!!Retreat!!Retreat!!Game {_score = 0, _units = [Unit {_health = 10, _position = Poin!t {_x = 33.5, _y = 37.0}},Unit {_health = 12, _position = Point !{_x = 31.0, _y = 31.0}},Unit {_health = 5, _position = Point {_x! = 30.0, _y = 32.1}}], _boss = Unit {_health = 70, _position = P!oint {_x = 30.0, _y = 30.0}}}

Page 29: λ | Lenses

References• FPComplete Lens Tutorial

https://www.fpcomplete.com/school/to-infinity-and-beyond/pick-of-the-week/a-little-lens-starter-tutorial

• Programming imperatively using Haskell http://www.haskellforall.com/2013/05/program-imperatively-using-haskell.html

• Lenses, Folds and Traversals http://lens.github.io

• Lenses In Pictures http://adit.io/posts/2013-07-22-lenses-in-pictures.html

Page 30: λ | Lenses

Thank you!