# Lenses

## Wofür brauchen wir das überhaupt?

Die Idee dahinter ist, dass man Zugriffsabstraktionen über Daten verknüpfen
kann. Als einfachen Datenstruktur kann man einen Record mit der entsprechenden
Syntax nehmen.

### Beispiel

~~~ { .haskell }
data Person = P { name :: String
                , addr :: Address
                , salary :: Int }
data Address = A { road :: String
                 , city :: String
                 , postcode :: String }
-- autogeneriert unten anderem: addr :: Person -> Address
    
    setName :: String -> Person -> Person
    setName n p = p { name = n } --record update notation
    
    setPostcode :: String -> Person -> Person
    setPostcode pc p
        = p { addr = addr p { postcode = pc } }
    -- update of a record inside a record
~~~~~~~~~~~~~~~~~~

### Probleme

Probleme mit diesem Code:

- für 1-Dimensionale Felder ist die record-syntax ok.
- tiefere Ebenen nur umständlich zu erreichen
- eigentlich wollen wir nur pe in p setzen, müssen aber über addr etc. gehen.
- wir brauchen wissen über die "Zwischenstrukturen", an denen wir nicht
  interessiert sind

### Was wir gern hätten

~~~ { .haskell }
data Person = P { name :: String
                , addr :: Address
                , salary :: Int }
-- a lens for each field
lname   :: Lens' Person String
laddr   :: Lens' Person Adress
lsalary :: Lens' Person Int
-- getter/setter for them
view    :: Lens' s a -> s -> a
set     :: Lens' s a -> a -> s -> s
-- lens-composition
composeL :: Lens' s1 s2 -> Lens s2 a -> Lens' s1 a
~~~~~~~~~~~~~~~~~~

### Wie uns das hilft

Mit diesen Dingen (wenn wir sie hätten) könnte man dann

~~~ { .haskell }
data Person = P { name :: String
                , addr :: Address
                , salary :: Int }
data Address = A { road :: String
                 , city :: String
                 , postcode :: String }
setPostcode :: String -> Person -> Person
setPostcode pc p
    = set (laddr `composeL` lpostcode) pc p
~~~~~~~~~~~~~~~~~~

machen und wäre fertig.

## Trivialer Ansatz

### Getter/Setter als Lens-Methoden

~~~ { .haskell }
data LensR s a = L { viewR :: s -> a
                   , setR  :: a -> s -> s }

composeL (L v1 u1) (L v2 u2)
  = L (\s -> v2 (v1 s))
      (\a s -> u1 (u2 a (v1 s)) s)
~~~~~~~~~~~~~~~~~~

### Wieso ist das schlecht?

- extrem ineffizient

Auslesen traversiert die Datenstruktur, dann wird die Funktion angewendet und
zum setzen wird die Datenstruktur erneut traversiert:

~~~ { .haskell }
over :: LensR s a -> (a -> a) -> s -> s
over ln f s = setR l (f (viewR l s)) s
~~~~~~~~~~~~~~~~~~

- Lösung: modify-funktion hinzufügen

~~~ { .haskell }
data LensR s a
   = L { viewR :: s -> a
       , setR  :: a -> s -> s
       , mod   :: (a->a) -> s -> s
       , modM  :: (a->Maybe a) -> s -> Maybe s
       , modIO :: (a->IO a) -> s -> IO s }
~~~~~~~~~~~~~~~~~~

Neues Problem: Für jeden Spezialfall muss die Lens erweitert werden.

### Something in common

Man kann alle Monaden abstrahieren. Functor reicht schon:

~~~ { .haskell }
data LensR s a
   = L { viewR :: s -> a
       , setR  :: a -> s -> s
       , mod   :: (a->a) -> s -> s
       , modF  :: Functor f => (a->f a) -> s -> f s }
~~~~~~~~~~~~~~~~~~

Idee: Die 3 darüberliegenden durch modF ausdrücken.

### Typ einer Lens

Wenn man das berücksichtigt, dann hat einen Lens folgenden Typ:

~~~ {.haskell}
type Lens' s a = forall f. Functor f
                           => (a -> f a) -> s -> f s
~~~

Allerdings haben wir dann noch unseren getter/setter:

~~~ {.haskell}
data LensR s a = L { viewR :: s -> a
                   , setR :: a -> s -> s }
~~~

Stellt sich raus: Die sind isomorph! Auch wenn die von den Typen her komplett
anders aussehen.

## Benutzen einer Lens als Setter

~~~ { .haskell }
set :: Lens' s a -> (a -> s -> s)
set ln a s = --...umm...
--:t ln => (a -> f a) -> s -> f s
--            => get s out of f s to return it
~~~~~~

Wir können für f einfach die "Identity"-Monade nehmen, die wir nachher wegcasten
können.

~~~ { .haskell }
newtype Identity a = Identity a
-- Id :: a -> Identity a

runIdentity :: Identity s -> s
runIdentity   (Identity x) = x

instance Functor Identity where
    fmap f (Identity x) = Identity (f x)
~~~~~~~~~~~~~~~~~~

somit ist set einfach nur

~~~ { .haskell }
set :: Lens' s a -> (a -> s -> s)
set ln x s
   = runIdentity (ls set_fld s)
   where
     set_fld :: a -> Identity a
     set_fld _ = Identity x
     -- a was the OLD value.
     -- We throw that away and set the new value
~~~~~~

oder kürzer (für nerds wie den Autor der Lens-Lib)

~~~ {.haskell }
set :: Lens' s a -> (a -> s -> s)
set ln x = runIdentity . ln (Identity . const x)
~~~

## Benutzen einer Lens als Modify

Dasselbe wie Set, nur dass wir den Parameter nicht entsorgen, sondern in die
mitgelieferte Funktion stopfen.

~~~ {.haskell}
over :: Lens' s a -> (a -> a) -> s -> s
over ln f = runIdentity . ln (Identity . f)
~~~

## Benutzen einer Lens als Getter

~~~ { .haskell }
view :: Lens' s a -> (s -> a)
view ln s = --...umm...
--:t ln => (a -> f a) -> s -> f s
--            => get a out of the (f s) return-value
--            Wait, WHAT?
~~~~~~

Auch hier gibt es einen netten Funktor. Wir packen das "a" einfach in das "f"
und werfen das "s" am Ende weg.

~~~ { .haskell }
newtype Const v a = Const v

getConst :: Const v a -> v
getConst (Const x) = x

instance Functor (Const v) where
    fmap f (Const x) = Const x
    -- throw f away. Nothing changes our const!
~~~~~~

somit ergibt sich

~~~ { .haskell }
view :: Lens' s a -> (s -> a)
view ln s 
  = getConst (ln Const s)
              -- Const :: s -> Const a s
~~~~~~

oder nerdig

~~~ {.haskell}
view :: Lens' s a -> (s -> a)
view ln = getConst . ln Const
~~~

## Lenses bauen

Nochmal kurz der Typ:

~~~ {.haskell}
type Lens' s a = forall f. Functor f
                     => (a -> f a) -> s -> f s
~~~

Für unser Personen-Beispiel vom Anfang:

~~~ { .haskell }
data Person = P { _name :: String, _salary :: Int }

name :: Lens' Person String
-- name :: Functor f => (String -> f String)
--                    -> Person -> f Person

name elt_fn (P n s)
  = fmap (\n' -> P n' s) (elt_fn n)
-- fmap :: Functor f => (a->b) -> f a -> f b - der Funktor, der alles verknüpft
-- \n' -> .. :: String -> Person - Funktion um das Element zu lokalisieren (WO wird ersetzt/gelesen/...)
-- elt_fn n  :: f String         - Funktion um das Element zu verändern (setzen, ändern, ...)
~~~~~~

Die Lambda-Funktion ersetzt einfach den Namen. Häufig sieht man auch

~~~ {.haskell}
name elt_fn (P n s)
  = (\n' -> P n' s) <$> (elt_fn n)
--  |    Focus    |     |Function|
~~~

## Wie funktioniert das intern?

~~~ { .haskell }
view name (P {_name="Fred", _salary=100})
   -- inline view-function
= getConst (name Const (P {_name="Fred", _salary=100})
   -- inline name
= getConst (fmap (\n' -> P n' 100) (Const "Fred"))
   -- fmap f (Const x) = Const x - Definition von Const
= getConst (Const "Fred")
   -- getConst (Const x) = x
= "Fred"
~~~~~~

Dieser Aufruf hat KEINE Runtime-Kosten, weil der Compiler direkt die Adresse des
Feldes einsetzen kann. Der gesamte Boilerplate-Code wird vom Compiler
wegoptimiert.

Dies gilt für jeden Funktor mit newtype, da das nur ein Typalias ist.

## Composing Lenses und deren Benutzung

Wie sehen denn die Typen aus?

Wir wollen ein

> Lens' s1 s2 -> Lens' s2 a -> Lens' s1 a

Wir haben 2 Lenses

> ln1 :: (s2 -> f s2) -> (s1 -> f s1)
> ln2 :: (a -> f a) -> (s2 -> f s2)

wenn man scharf hinsieht, kann man die verbinden

> ln1 . ln2 :: (a -> f s) -> (s1 -> f s1)

und erhält eine Lens. Sogar die Gewünschte!  
Somit ist Lens-Composition einfach nur Function-Composition (.).

## Automatisieren mit Template-Haskell

Der Code um die Lenses zu bauen ist für records immer Identisch:

~~~ { .haskell }
data Person = P { _name :: String, _salary :: Int }

name :: Lens' Person String
name elt_fn (P n s) = (\n' -> P n' s) <$> (elt_fn n)
~~~~~~

Daher kann man einfach

~~~ { .haskell }
import Control.Lens.TH
data Person = P { _name :: String, _salary :: Int }

$(makeLenses ''Person)
~~~~~~

nehmen, was einem eine Lens für "name" und eine Lens für "salary" generiert.  
Mit anderen Templates kann man auch weitere Dinge steuern (etwa wofür Lenses
generiert werden, welches Prefix (statt \_) man haben will etc. pp.).  

Will man das aber haben, muss man selbst in den Control.Lens.TH-Code schauen.

## Lenses für den Beispielcode

~~~ { .haskell }
import Control.Lens.TH

data Person = P { _name :: String
                , _addr :: Address
                , _salary :: Int }
data Address = A { _road :: String
                 , _city :: String
                 , _postcode :: String }

$(makeLenses ''Person)
$(makeLenses ''Address)

setPostcode :: String -> Person -> Person
setPostcode pc p = set (addr . postcode) pc p
~~~~~~~~~~~~~~~~~~

## Shortcuts mit "Line-Noise"

~~~ { .haskell }
-- ...

setPostcode :: String -> Person -> Person
setPostcode pc p = addr . postcode .~ pc     $ p
--                 |   Focus     |set|to what|in where

getPostcode :: Person -> String
getPostcode p = p   ^. $ addr . postcode
--            |from|get|    Focus       |
~~~~~~~~~~~~~~~~~~

Es gibt drölf-zillionen weitere Infix-Operatoren (für Folds,
Listenkonvertierungen, -traversierungen, ...)

## Virtuelle Felder

Man kann mit Lenses sogar Felder emulieren, die gar nicht da sind. Angenommen
folgender Code:

~~~ { .haskell }
data Temp = T { _fahrenheit :: Float }

$(makeLenses ''Temp)
-- liefert Lens: fahrenheit :: Lens Temp Float

centigrade :: Lens Temp Float
centigrade centi_fn (T faren)
  = (\centi' -> T (cToF centi'))
    <$> (centi_fn (fToC faren))
-- cToF & fToC as Converter-Functions defined someplace else
~~~~~~~~~~~~~~~~~~

Hiermit kann man dann auch Funktionen, die auf Grad-Celsius rechnen auf Daten
anwenden, die eigenlich nur Fahrenheit speichern, aber eine Umrechnung
bereitstellen.  Analog kann man auch einen Zeit-Datentypen definieren, der
intern mit Sekunden rechnet (und somit garantiert frei von Fehlern wie -3
Minuten oder 37 Stunden ist)

## Non-Record Strukturen

Das ganze kann man auch parametrisieren und auf Non-Record-Strukturen anwenden.
Beispielhaft an einer Map verdeutlicht:

~~~ { .haskell }
-- from Data.Lens.At
at :: Ord k => k -> Lens' (Map k v) (Maybe v)

-- oder identisch, wenn man die Lens' auflöst:
at :: Ord k, forall f. Functor f => k -> (Maybe v -> f Maybe v) -> Map k v -> f Map k v

at k mb_fn m
  = wrap <$> (mb_fn mv)
  where
    mv = Map.lookup k m
    
    wrap :: Maybe v -> Map k v
    wrap (Just v') = Map.insert k v' m
    wrap Nothing   = case mv of
                       Nothing -> m
                       Just _  -> Map.delete k m

-- mb_fn :: Maybe v -> f Maybe v
~~~~~~~~~~~~~~~~~~

## Weitere Beispiele

- Bitfields auf Strukturen die Bits haben (Ints, ...) in Data.Bits.Lens
- Web-scraper in Package hexpat-lens  

  ~~~ { .haskell }
  p ^.. _HTML' . to allNodes
               . traverse . named "a"
               . traverse . ix "href"
               . filtered isLocal
               . to trimSpaces
  ~~~~~~~~~~~~~~~~~~

  Zieht alle externen Links aus dem gegebenen HTML-Code in p um weitere ziele
  fürs crawlen zu finden.

## Erweiterungen

Bisher hatten wir Lenses nur auf Funktoren F. Die nächstmächtigere Klasse ist
Applicative.

~~~ { .haskell }
type Traversal' s a = forall f. Applicative f
                             => (a -> f a) -> (s -> f s)
~~~~~~~~~~~~~~~~~~

Da wir den Container identisch lassen (weder s noch a wurde angefasst) muss sich
etwas anderes ändern. Statt eines einzelnen Focus erhalten wir viele Foci.

Was ist ein Applicative überhaupt? Eine schwächere Monade (nur 1x Anwendung und
kein Bind - dafür kann man die beliebig oft hintereinanderhängen).

~~~ { .haskell }
class Functor f => Applicative f where
  pure  :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b

-- Monade als Applicative:
pure = return
mf <*> mx = do { f <- mf; x <- mx; return (f x) }
~~~~~~~~~~~~~~~~~~

Recap: Was macht eine Lens:

~~~ { .haskell }
data Adress = A { _road :: String
                , _city :: String
                , _postcode :: String }

road :: Lens' Adress String
road elt_fn (A r c p) = (\r' -> A r' c p) <$> (elt_fn r)
--                      |    "Hole"     |     | Thing to put in|
~~~~~~~~~~~~~~~~~~

Wenn man nun road & city gleichzeitig bearbeiten will:

~~~ { .haskell }
addr_strs :: Traversal' Address String
addr_strs elt_fn (A r c p)
  = ... (\r' c' -> A r' c' p)    .. (elt_fn r) .. (elt_fn c) ..
--      | function with 2 "Holes"|  first Thing |  second Thing
~~~~~~~~~~~~~~~~~~

fmap kann nur 1 Loch stopfen, aber nicht mit n Löchern umgehen. Applicative mit
<*> kann das.  
Somit gibt sich

~~~ { .haskell }
addr_strs :: Traversal' Address String
addr_strs elt_fn (A r c p)
  = pure           (\r' c' -> A r' c' p)  <*> (elt_fn r) <*> (elt_fn c)
--  lift in Appl. | function with 2 "Holes"|  first Thing |  second Thing
-- oder kürzer
addr_strs :: Traversal' Address String
addr_strs elt_fn (A r c p)
  = (\r' c' -> A r' c' p)  <$> (elt_fn r) <*> (elt_fn c)
-- pure x <*> y == x <$> y
~~~~~~~~~~~~~~~~~~

Wie würd eine modify-funktion aussehen?

~~~ {.haskell}
over :: Lens' s a -> (a -> a) -> s -> s
over ln f = runIdentity . ln (Identity . f)

over :: Traversal' s a -> (a -> a) -> s -> s
over ln f = runIdentity . ln (Identity . f)
~~~

Der Code ist derselbe - nur der Typ ist generischer. Auch die anderen Dinge
funktioniert diese Erweiterung (für Identity und Const muss man noch ein paar
dummy-Instanzen schreiben um sie von Functor auf Applicative oder Monad zu heben
- konkret reicht hier die Instanzierung von Monoid). In der Lens-Library ist
  daher meist Monad m statt Functor f gefordert.

## Wozu dienen die Erweiterungen?

Man kann mit Foci sehr selektiv vorgehen. Auch kann man diese durch Funktionen
steuern. Beispisweise eine Funktion anwenden auf

- Jedes 2. Listenelement
- Alle graden Elemente in einem Baum
- Alle Namen in einer Tabelle, deren Gehalt > 10.000€ ist

Traversals und Lenses kann man trivial kombinieren (`lens . lens` => `lens`,
`lens . traversal` => `traversal` etc.)

## Wie es in Lens wirklich aussieht

In diesem Artikel wurde nur auf Monomorphic Lenses eingegangen. In der richtigen
Library ist eine Lens

~~~ {.haskell}
type Lens' s a = Lens s s a a
type Lens s t a b = forall f. Functor f => (a -> f b) -> (s -> f t)
~~~

sodass sich auch die Typen ändern können um z.B. automatisch einen Konvertierten
(sicheren) Typen aus einer unsicheren Datenstruktur zu geben.

Die modify-Funktion over ist auch

~~~ {.haskell}
> over :: Profunctor p => Setting p s t a b -> p a b -> s -> t
~~~

> *Edward is deeply in thrall to abstractionitis* - Simon Peyton Jones

Lens alleine definiert 39 newtypes, 34 data-types und 194 Typsynonyme...  
Ausschnitt

~~~ { .haskell }
-- traverseOf :: Functor f => Iso s t a b           -> (a -> f b) -> s -> f t
-- traverseOf :: Functor f => Lens s t a b          -> (a -> f b) -> s -> f t
-- traverseOf :: Applicative f => Traversal s t a b -> (a -> f b) -> s -> f t

traverseOf :: Over p f s t a b -> p a (f b) -> s -> f t
~~~~~~~~~~~~~~~~~~

dafuq?
