lens: from the ground up

lens: from the ground up

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)

42d9867a0fee0fa6de6534e9df0f1e9b?s=128

Mark Hibberd

February 26, 2014
Tweet

Transcript

  1. 4.

    data Lens a b = Lens { get :: a

    -> b , set :: b -> a -> a } intuitions
  2. 5.

    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. 6.

    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. 7.

    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. 8.

    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. 9.

    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. 10.

    but… data Safety = Safety { _readOnly :: String }

    ! readOnly :: Lens Safety String readOnly = Lens _readOnly (error "don't do this")
  8. 11.

    but… read only / write only matters data Safety =

    Safety { _readOnly :: String } ! readOnly :: Lens Safety String readOnly = Lens _readOnly (error "don't do this")
  9. 12.

    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. 13.

    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. 14.

    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. 15.

    but… data OneOf = First String | Second Int !

    first :: Lens OneOf (Maybe String) first = undefined ! first :: Lens OneOf (Maybe String) first = undefined
  13. 16.

    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. 17.

    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. 18.

    failed experiments data Store s a = Store (s ->

    a) s ! data Lens a b = Lens (a -> Store b a) ! ! ! ! ! ! ! !
  16. 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
  17. 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
  18. 21.

    ! type Lens’ a b = forall f. Functor f

    => (b -> f b) -> a -> f a back to the drawing board
  19. 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?”
  20. 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 ! !
  21. 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 !
  22. 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
  23. 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
  24. 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) ! ! !
  25. 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 ! ! !
  26. 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) ! ! !
  27. 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 ! ! !
  28. 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 ! ! !
  29. 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
  30. 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 ! !
  31. 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 !
  32. 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
  33. 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
  34. 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) ! ! !
  35. 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 ! ! !
  36. 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 ! ! !
  37. 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 ! ! ! !
  38. 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) !
  39. 43.
  40. 44.

    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 ! ! ! ! !
  41. 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 x . y :: Lens a c ! ! ! ! !
  42. 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 ! ! ! ! !
  43. 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) ! ! ! ! !
  44. 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 ! ! !
  45. 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 !
  46. 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 !
  47. 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
  48. 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
  49. 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
  50. 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
  51. 55.

    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)
  52. 56.

    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)
  53. 57.

    ! 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
  54. 58.

    ! 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
  55. 59.

    ! 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) !
  56. 60.

    ! 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) !
  57. 61.

    ! 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) !
  58. 62.

    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
  59. 63.

    multiplate type Traversal a a’ b b’ = forall f.

    Applicative f => (b -> f b’) -> a -> f a’
  60. 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) !
  61. 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
  62. 66.

    type Iso s t a b = forall p f.

    (Profunctor p, Functor f) => p a (f b) -> p s (f t) iso
  63. 67.
  64. 68.
  65. 69.

    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