$30 off During Our Annual Pro Sale. View Details »

lens: from the ground up

Mark Hibberd
February 26, 2014

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)

Mark Hibberd

February 26, 2014
Tweet

More Decks by Mark Hibberd

Other Decks in Programming

Transcript

  1. lens
    @markhibberd
    from the ground up

    View Slide

  2. motivations

    View Slide

  3. the ground up

    View Slide

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

    View Slide

  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!

    View Slide

  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)

    View Slide

  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!

    View Slide

  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 })

    View Slide

  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

    View Slide

  10. but…
    data Safety =
    Safety { _readOnly :: String }
    !
    readOnly :: Lens Safety String
    readOnly =
    Lens _readOnly (error "don't do this")

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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?”

    View Slide

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

    View Slide

  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
    !

    View Slide

  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

    View Slide

  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

    View Slide

  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)
    !
    !
    !

    View Slide

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

    View Slide

  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)
    !
    !
    !

    View Slide

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

    View Slide

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

    View Slide

  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

    View Slide

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

    View Slide

  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
    !

    View Slide

  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

    View Slide

  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

    View Slide

  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)
    !
    !
    !

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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)
    !

    View Slide

  42. functional elegance

    View Slide

  43. composition
    !
    type Lens’ a b =
    forall f. Functor f => (b -> f b) -> a -> f a

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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)
    !
    !
    !
    !
    !

    View Slide

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

    View Slide

  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
    !

    View Slide

  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
    !

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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)

    View Slide

  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)

    View Slide

  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

    View Slide

  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

    View Slide

  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)
    !

    View Slide

  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)
    !

    View Slide

  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)
    !

    View Slide

  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

    View Slide

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

    View Slide

  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)
    !

    View Slide

  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

    View Slide

  66. type Iso s t a b =
    forall p f. (Profunctor p, Functor f) =>
    p a (f b) -> p s (f t)
    iso

    View Slide

  67. code

    View Slide

  68. gotchas

    View Slide

  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

    View Slide

  70. fin
    @markhibberd

    View Slide