Lens is a Haskell package that provides access (read, write, modify etc) into the middle of a data structure, or container.

```
module Main where
import Control.Lens ( lens, Lens', Lens, view, set )
-- imported from the package lens
foo :: (Int, (Int, Bool))
= (1, (2, True))
foo
-- Task 1: Read the first element of foo
read1st :: (a, b) -> a
= x
read1st (x, _) -- >>> read1st foo
-- 1
-- Task 2: Write the 3 to the second element of foo
write2nd :: (a, (b, c)) -> b -> (a, (b, c))
= (x, (newy, z))
write2nd (x, (y, z)) newy
-- >>> write2nd foo 3
-- (1,(3,True))
-- Task 3: Write the False to the second element of foo
write2ndHeter :: (a, (b, c)) -> d -> (a, (d, c))
= (x, (newy, z))
write2ndHeter (x, (y, z)) newy
-- >>> write2ndHeter foo False
-- (1,(False,True))
-- Lens
-- Lens' type constructor assumes two parameters: object and focus.
-- to implement a lens, you need to provide a getter and a setter
_left :: Lens' (a, b) a
= lens getter setter
_left where
getter :: (a, b) -> a
= x
getter (x, _) setter :: (a, b) -> a -> (a, b)
= (newx, y)
setter (_, y) newx
_right :: Lens' (a, b) b
= lens getter setter
_right where
getter :: (a, b) -> b
= y
getter (_, y) setter :: (a, b) -> b -> (a, b)
= (x, newy)
setter (x, _) newy
-- use view to read, use set to write
read1st' :: (a, b) -> a
= view _left
read1st' -- >>> read1st' foo
-- 1
-- you can compose (.) lens to get a new lens
write2nd' :: (a, (b, c)) -> b -> (a, (b, c))
= set _2nd new obj
write2nd' obj new where _2nd = _right . _left
-- >>> write2nd' foo 3
-- (1,(3,True))
-- to implement write2ndHeter, which modifies the type of the object,
-- we need to reach the full power of Lens.
-- use Lens instead of Lens'
-- type Lens' s a = Lens s s a a
-- Lens type constructor assumes four parameters:
-- object, new object, focus, new focus
_left' :: Lens (a, b) (a', b) a a'
= lens getter setter
_left' where
getter :: (a, b) -> a
= x
getter (x, _) setter :: (a, b) -> a' -> (a', b)
= (newx, y)
setter (_, y) newx
_right' :: Lens (a, b) (a, b') b b'
= lens getter setter
_right' where
getter :: (a, b) -> b
= y
getter (_, y) setter :: (a, b) -> b' -> (a, b')
= (x, newy)
setter (x, _) newy
write2ndHeter' :: (a, (b, c)) -> d -> (a, (d, c))
= set _2nd new obj
write2ndHeter' obj new where _2nd = _right' . _left'
-- >>> write2ndHeter' foo False
-- (1,(False,True))
main :: IO ()
= putStrLn "Hello, Lens!" main
```

## TODO

- Implementing Lens