Slide 1

Slide 1 text

lens @markhibberd from the ground up

Slide 2

Slide 2 text

motivations

Slide 3

Slide 3 text

(defrecord Address [street city postcode]) ! (defrecord Person [name age address]) ! (defrecord User [uid username identity password]) records

Slide 4

Slide 4 text

(def home (->Address "road" "place" 4000)) ! (def mark (->Person "mark" 99 home)) ! (def user (->User 3365 "mth" mark "6aefd2842be62cd470709b27aedc7db7")) records (defrecord Address [street city postcode]) ! (defrecord Person [name age address]) ! (defrecord User [uid username identity password])

Slide 5

Slide 5 text

! (def updated (update-in user [:identity] (fn [person] (update-in person [:address] (fn [address] (update-in address [:postcode] #(+ 4 %))))))) records (defrecord Address [street city postcode]) ! (defrecord Person [name age address]) ! (defrecord User [uid username identity password])

Slide 6

Slide 6 text

! (update-in user [:identity :address :postcode] #(+ 2 %)) records (defrecord Address [street city postcode]) ! (defrecord Person [name age address]) ! (defrecord User [uid username identity password]) Can we do better?!

Slide 7

Slide 7 text

the ground up

Slide 8

Slide 8 text

; get :: a -> b ; set :: a -> b -> a ! (defrecord Lens [getter setter]) ! (defn lget [lens a] ((:getter lens) a)) ! (defn lset [lens a b] ((:setter lens) a b)) intuitions

Slide 9

Slide 9 text

; get :: a -> b ; set :: a -> b -> a ! (defrecord Lens [getter setter]) ! (defn lget [lens a] ((:getter lens) a)) ! (defn lset [lens a b] ((:setter lens) a b)) set-get ==> (get l (set l a b)) == b ! get-set ==> (set l a (get l a)) == a ! set-set ==> (set l (set l b a) c) == (set l a c) intuitions Pierce’s laws!

Slide 10

Slide 10 text

but… ! (defn lmodify [lens a func] ((:setter lens) a (func ((:getter lens) a)))) ! (defn lcompose [lens-a-b lens-b-c] (->Lens (fn [a] (lget lens-b-c (lget lens-a-b a))) (fn [a c] (lset lens-a-b a (lset lens-b-c (lget lens-a-b a) c)))))

Slide 11

Slide 11 text

but… efficiency matters composition matters partiality matters elegance matters

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board ! (deffn set [lens a b] (“can we?”)) ! (deffn get [lens a] (“can we?”))

Slide 15

Slide 15 text

! (defprotocol Functor (fmap [functor f] "fmap :: f a -> (a -> b) -> f b")) aside: what is a functor

Slide 16

Slide 16 text

! (defprotocol Functor (fmap [functor f] "fmap :: f a -> (a -> b) -> f b")) ! (defrecord List [wrapped] Functor (fmap [functor f] (List. (map f (:wrapped functor))))) aside: what is a functor

Slide 17

Slide 17 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Id [runId] Functor (fmap [functor f] (Id. (f (:runId functor))))) ! (deffn -set [lens a] (???)) ! ! !

Slide 18

Slide 18 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Id [runId] Functor (fmap [functor f] (Id. (f (:runId functor))))) ! (deffn -set [lens a b] (let [b-ib (fn [bb] (->Id b)) -- b -> Id b ] (“???”)))

Slide 19

Slide 19 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Id [runId] Functor (fmap [functor f] (Id. (f (:runId functor))))) ! (deffn -set [lens a b] (let [b-ib (fn [bb] (->Id b)) -- b -> Id b a-ia (lens b-ib) -- a -> Id a ] (“???”)))

Slide 20

Slide 20 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Id [runId] Functor (fmap [functor f] (Id. (f (:runId functor))))) ! (deffn -set [lens a b] (let [b-ib (fn [bb] (->Id b)) -- b -> Id b a-ia (lens b-ib) -- a -> Id a ia (a-ia a)] -- Id a (“???”)))

Slide 21

Slide 21 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Id [runId] Functor (fmap [functor f] (Id. (f (:runId functor))))) ! (deffn -set [lens a b] (let [b-ib (fn [bb] (->Id b)) -- b -> Id b a-ia (lens b-ib) -- a -> Id a ia (a-ia a)] -- Id a (:runId ia))) -- a

Slide 22

Slide 22 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord ??? [???] Functor (fmap [functor f] ???)) ! (deffn -get [lens a] (???)) ! ! ! !

Slide 23

Slide 23 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Const [runConst] Functor (fmap [functor f] (Const. (:runConst functor)))) ! (deffn -get [lens a] (???) ! ! !

Slide 24

Slide 24 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Const [runConst] Functor (fmap [functor f] (Const. (:runConst functor)))) ! (deffn -get [lens a] (let [b-cb (fn [b] (->Const b)) -- b -> Const b ] (???)))

Slide 25

Slide 25 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Const [runConst] Functor (fmap [functor f] (Const. (:runConst functor)))) ! (deffn -get [lens a] (let [b-cb (fn [b] (->Const b)) -- b -> Const b a-ca (lens b-cb) -- a -> Const a ] (???)))

Slide 26

Slide 26 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Const [runConst] Functor (fmap [functor f] (Const. (:runConst functor)))) ! (deffn -get [lens a] (let [b-cb (fn [b] (->Const b)) -- b -> Const b a-ca (lens b-cb) -- a -> Const a ca (a-ca a)] -- Const a (???)))

Slide 27

Slide 27 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Const [runConst] Functor (fmap [functor f] (Const. (:runConst functor)))) ! (deffn -get [lens a] (let [b-cb (fn [b] (->Const b)) -- b -> Const b a-ca (lens b-cb) -- a -> Const a ca (a-ca a)] -- Const a (:runConst ca))) -- a

Slide 28

Slide 28 text

! type Lens’ a b = forall f. Functor f => (b -> f b) -> a -> f a back to the drawing board (defrecord Id [runId] Functor (fmap [functor f] (Id. (f (:runId functor))))) ! (deffn -modify [lens a f] (let [b-ib (fn [bb] (->Id (f bb))) -- b -> Id b a-ia (lens b-ib) -- a -> Id a ia (a-ia a)] -- Id a (:runId ia))) -- a

Slide 29

Slide 29 text

functional elegance

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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 (comp x y) :: Lens a c ! ! ! ! !

Slide 33

Slide 33 text

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) (comp x y) :: Lens a c ! ! ! ! !

Slide 34

Slide 34 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! ! ! ! !

Slide 35

Slide 35 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! ! !

Slide 36

Slide 36 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! (defn comp [f g] (fn [a] (f (g a))))

Slide 37

Slide 37 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j !

Slide 38

Slide 38 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i !

Slide 39

Slide 39 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b

Slide 40

Slide 40 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a

Slide 41

Slide 41 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a, h :: c -> f c

Slide 42

Slide 42 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a, h :: c -> f c (comp x y) :: h -> j

Slide 43

Slide 43 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a, h :: c -> f c (comp x y) :: h -> j :: (c -> f c) -> (a -> f a)

Slide 44

Slide 44 text

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) (comp x y) :: Lens a c :: (c -> f c) -> (a -> f a) ! (comp) :: (i -> j) -> (h -> i) -> h -> j ! x :: i -> j, y :: h -> i i :: b -> f b, j :: a -> f a, h :: c -> f c (comp x y) :: h -> j :: (c -> f c) -> (a -> f a)

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t) prisms / co-lens

Slide 48

Slide 48 text

code

Slide 49

Slide 49 text

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 • this talk in haskell: • https://speakerdeck.com/markhibberd/lens-from-the-ground-up

Slide 50

Slide 50 text

fin @markhibberd