Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

lens: from the ground up (at BFPG)

lens: from the ground up (at BFPG)

A look at functional lenses in general, and the haskell "lens" library specifically. This talk walks through why lenses are encoded the way they are, and builds up to demonstrations of the lens library.

The demonstration code is available at https://github.com/markhibberd/lens-talk (see script.org and src/*.hs)

This is a slightly different version to what was presented at fp-syd.

Mark Hibberd

March 17, 2014
Tweet

More Decks by Mark Hibberd

Other Decks in Programming

Transcript

  1. data Lens a b = Lens { get :: a

    -> b , set :: b -> a -> a } intuitions
  2. data Lens a b = Lens { get :: a

    -> b , set :: b -> a -> a } intuitions set-get ==> get l (set l b a) == b ! get-set ==> set l (get l a) a == a ! set-set ==> set l c (set l b a) == set l c a Pierce’s laws!
  3. but… modify :: Lens a b -> (b -> b)

    -> a -> a modify l f a = set l (f (get l a)) a ! compose :: Lens a b -> Lens b c -> Lens a c compose l j = Lens (\a -> get j (get l a)) (\c a -> set l (set j c (get l a)) a)
  4. but… modify :: Lens a b -> (b -> b)

    -> a -> a modify l f a = set l (f (get l a)) a ! compose :: Lens a b -> Lens b c -> Lens a c compose l j = Lens (\a -> get j (get l a)) (\c a -> set l (set j c (get l a)) a) efficiency matters!
  5. but… data Wedge a = Wedge { _name :: String,

    _val :: a } ! name :: Lens (Wedge a) String name = Lens _name (\n w -> w { _name = n }) ! value :: Lens (Wedge a) a value = Lens _val (\v w -> w { _val = v })
  6. but… data Wedge a = Wedge { _name :: String,

    _val :: a } ! name :: Lens (Wedge a) String name = Lens _name (\n w -> w { _name = n }) ! value :: Lens (Wedge a) a value = Lens _val (\v w -> w { _val = v }) polymorphic update matters
  7. but… data Safety = Safety { _readOnly :: String }

    ! readOnly :: Lens Safety String readOnly = Lens _readOnly (error "don't do this")
  8. but… read only / write only matters data Safety =

    Safety { _readOnly :: String } ! readOnly :: Lens Safety String readOnly = Lens _readOnly (error "don't do this")
  9. but… (&&&) :: Lens a b -> Lens a c

    -> Lens a (b, c) (&&&) l j = Lens (\a -> (get l a, get j a)) (\(b, c) a -> set j c (set l b a))
  10. but… (&&&) :: Lens a b -> Lens a c

    -> Lens a (b, c) (&&&) l j = Lens (\a -> (get l a, get j a)) (\(b, c) a -> set j c (set l b a)) not a lens
  11. but… (&&&) :: Lens a b -> Lens a c

    -> Lens a (b, c) (&&&) l j = Lens (\a -> (get l a, get j a)) (\(b, c) a -> set j c (set l b a)) composition matters not a lens
  12. but… data OneOf = First String | Second Int !

    first :: Lens OneOf (Maybe String) first = undefined ! first :: Lens OneOf (Maybe String) first = undefined
  13. but… data OneOf = First String | Second Int !

    first :: Lens OneOf (Maybe String) first = undefined ! first :: Lens OneOf (Maybe String) first = undefined not a lens
  14. but… data OneOf = First String | Second Int !

    first :: Lens OneOf (Maybe String) first = undefined ! first :: Lens OneOf (Maybe String) first = undefined not a lens partiality matters
  15. failed experiments data Store s a = Store (s ->

    a) s ! data Lens a b = Lens (a -> Store b a) ! ! ! ! ! ! ! !
  16. failed experiments data Store s a = Store (s ->

    a) s ! data Lens a b = Lens (a -> Store b a) ! ! ! ! ! ! ! ! data Lens a b = Lens { get :: a -> b , set :: b -> a -> a }
  17. failed experiments data Store s a = Store (s ->

    a) s ! data Lens a b = Lens (a -> Store b a) ! ! ! ! ! ! ! ! data Lens a b = Lens { get :: a -> b , set :: a -> b -> a }
  18. failed experiments data Store s a = Store (s ->

    a) s ! data Lens a b = Lens (a -> Store b a) ! ! ! ! ! ! ! ! data Lens a b = Lens { run :: a ->(b ,b -> a) }
  19. data Store s a = Store (s -> a) s

    ! data Lens a b = Lens (a -> Store b a) ! get :: Lens a b -> a -> b get (Lens l) a = case l a of Store _ s -> s ! set :: Lens a b -> b -> a -> a set (Lens l) b a = case l a of Store f _ -> f b failed experiments
  20. data Store s a = Store (s -> a) s

    ! data Lens a b = Lens (a -> Store b a) ! get :: Lens a b -> a -> b get (Lens l) a = case l a of Store _ s -> s ! set :: Lens a b -> b -> a -> a set (Lens l) b a = case l a of Store f _ -> f b polymorphic update matters composition matters failed experiments partiality matters read only / write only matters
  21. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board
  22. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board ! set :: Lens’ a b -> b -> a -> a set = error “can we?” ! get :: Lens’ a b -> a -> b get = error “can we?”
  23. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Identity a = Identity { runIdentity :: a } ! set :: Lens’ a b -> b -> a -> a set l b a = let x = const $ Identity b -- :: b -> Identity b in undefined ! !
  24. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Identity a = Identity { runIdentity :: a } ! set :: Lens’ a b -> b -> a -> a set l b a = let x = const $ Identity b -- :: b -> Identity b y = l x -- :: a -> Identity a in runIdentity z !
  25. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Identity a = Identity { runIdentity :: a } ! set :: Lens’ a b -> b -> a -> a set l b a = let x = const $ Identity b -- :: b -> Identity b y = l x -- :: a -> Identity a z = y a -- :: Identity a in undefined
  26. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Identity a = Identity { runIdentity :: a } ! set :: Lens’ a b -> b -> a -> a set l b a = let x = const $ Identity b -- :: b -> Identity b y = l x -- :: a -> Identity a z = y a -- :: Identity a in runIdentity z
  27. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Identity a = Identity { runIdentity :: a } ! set :: Lens’ a b -> b -> a -> a set l b a = runIdentity (l (const $ Identity b) a) ! ! !
  28. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Identity a = Identity { runIdentity :: a } ! set :: Lens’ a b -> b -> a -> a set l b a = runIdentity . l (const $ Identity b) $ a ! ! !
  29. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Identity a = Identity { runIdentity :: a } ! set :: Lens’ a b -> b -> a -> a set l b = runIdentity . l (const $ Identity b) ! ! !
  30. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype ??? a = ??? ! get :: Lens’ a b -> a -> b get l a = undefined ! ! !
  31. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l a = undefined ! ! !
  32. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l a = undefined ! ! ! ! instance Functor (Const x) where fmap _ = Const . runConst
  33. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l a = let x = Const -- :: b -> Const b b in undefined ! !
  34. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l a = let x = Const -- :: b -> Const b b y = l x -- :: a -> Const b a in undefined !
  35. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l a = let x = Const -- :: b -> Const b b y = l x -- :: a -> Const b a z = y a -- :: Const b a in undefined
  36. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l a = let x = Const -- :: b -> Const b b y = l x -- :: a -> Const b a z = y a -- :: Const b a in runConst z
  37. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l a = runConst (l Const a) ! ! !
  38. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l a = runConst . l Const $ a ! ! !
  39. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board newtype Const x a = Const x ! get :: Lens’ a b -> a -> b get l = runConst . l Const ! ! !
  40. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board set :: Lens’ a b -> b -> a -> a set l b = runIdentity . l (const $ Identity b) ! get :: Lens’ a b -> a -> b get l = runConst . l Const ! ! ! !
  41. ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board set :: Lens’ a b -> b -> a -> a set l b = runIdentity . l (const $ Identity b) ! get :: Lens’ a b -> a -> b get l = runConst . l Const ! modify :: Lens’ a b -> (b -> b) -> a modify l f = runIdentity . l (Identity . f) !
  42. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b y :: Lens b c x . y :: Lens a c ! ! ! ! !
  43. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c x . y :: Lens a c ! ! ! ! !
  44. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c ! ! ! ! !
  45. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! ! ! ! !
  46. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! ! !
  47. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j !
  48. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i !
  49. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b
  50. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a
  51. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a, h :: c -> f c
  52. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a, h :: c -> f c x . y :: h -> j
  53. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a, h :: c -> f c x . y :: h -> j :: (c -> f c) -> (a -> f a)
  54. function composition ! type Lens’ a b = forall f.

    Functor f => (b -> f b) -> a -> f a x :: Lens a b :: (b -> f b) -> (a -> f a) y :: Lens b c :: (c -> f c) -> (b -> f b) x . y :: Lens a c :: (c -> f c) -> (a -> f a) ! (.) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a, h :: c -> f c x . y :: h -> j :: (c -> f c) -> (a -> f a)
  55. ! type Lens a a’ b b’ = forall f.

    Functor f => (b -> f b’) -> a -> f a’ ! type Lens’ a b = Lens a a b b polymorphic update
  56. ! type Lens a a’ b b’ = forall f.

    Functor f => (b -> f b’) -> a -> f a’ ! type Simple f a b = f a a b b ! type Lens’ = Simple Lens polymorphic update
  57. ! type Lens a a’ b b’ = forall f.

    Functor f => (b -> f b’) -> a -> f a’ polymorphic update set :: Lens’ a b -> b -> a -> a set l b = runIdentity . l (const $ Identity b) ! get :: Lens’ a b -> a -> b get l = runConst . l Const ! modify :: Lens’ a b -> (b -> b) -> a modify l f = runIdentity . l (Identity . f) !
  58. ! type Lens a a’ b b’ = forall f.

    Functor f => (b -> f b’) -> a -> f a’ polymorphic update set :: Lens a a’ b b’ -> b’ -> a -> a’ set l b = runIdentity . l (const $ Identity b) ! get :: Lens a a’ b b’ -> a -> b’ get l = runConst . l Const ! modify :: Lens a a’ b b’ -> (b -> b’) -> a’ modify l f = runIdentity . l (Identity . f) !
  59. ! type Lens a a’ b b’ = forall f.

    Functor f => (b -> f b’) -> a -> f a’ polymorphic update set :: Lens a a’ b b’ -> b’ -> a -> a’ set l b = runIdentity . l (const $ Identity b) ! get :: Lens a a’ b b’ -> a -> b’ get l = runConst . l Const ! modify :: Lens a a’ b b’ -> (b -> b’) -> a’ modify l f = runIdentity . l (Identity . f) !
  60. type Getter s a = forall r. (a -> Const

    r a) -> s -> Const r s ! type Setter s t a b = (a -> Identity b) -> s -> Identity t mirrored lenses
  61. type Getter s a = forall r. (a -> Const

    r a) -> s -> Const r s ! type Setter s t a b = (a -> Identity b) -> s -> Identity t mirrored lenses lens . getter :: getter lens . setter :: setter getter . setter :: not a program
  62. multiplate type Fold a b = forall f. (Contravariant f,

    Applicative f) => (b -> f b) -> a -> f a ! type Traversal a a’ b b’ = forall f. Applicative f => (b -> f b’) -> a -> f a’
  63. multiplate type Fold a b = forall f. (Contravariant f,

    Applicative f) => (b -> f b) -> a -> f a ! type Traversal a a’ b b’ = forall f. Applicative f => (b -> f b’) -> a -> f a’ getter :: fold traversal :: fold lens :: traversal
  64. type Traversal a a’ b b’ = forall f. Applicative

    f => (b -> f b’) -> a -> f a’ multiplate set :: Traversal a a’ b b’ -> b’ -> a -> a’ set l b = runIdentity . l (const $ Identity b) ! get :: Traversal a a’ b b’ -> a -> b’ get l = runConst . l Const ! modify :: Traversal a a’ b b’ -> (b -> b’) -> a’ modify l f = runIdentity . l (Identity . f) !
  65. type Prism s t a b = forall p f.

    (Choice p, Applicative f) => p a (f b) -> p s (f t) prisms / co-lens prism :: traversal traversal :: fold lens :: traversal
  66. type Iso s t a b = forall p f.

    (Profunctor p, Functor f) => p a (f b) -> p s (f t) iso iso :: lens iso :: prism iso :: traversal iso :: getter iso :: setter
  67. references • Pierce’s original work on lenses / bidirectional programming:

    • http://www.cis.upenn.edu/~bcpierce/papers/index.shtml#Lenses • van Laarhoven’s original write-up: • http://www.twanvl.nl/blog/haskell/cps-functional-references • O’Connor’s coining of the term “van Laarhoven lens” and the insight into polymorphic update: • http://r6.ca/blog/20120623T104901Z.html • O’Connor’s multiplate paper (a.k.a. traversals): • http://arxiv.org/pdf/1103.2841v2.pdf • Kmett’s expanding on mirrored lens insights (a.k.a. read-only / write only): • http://comonad.com/reader/2012/mirrored-lenses/ • lens website, lots of links and video: • http://lens.github.io/ • git repo: • https://github.com/ekmett/lens • hackage: • http://hackage.haskell.org/package/lens