~williamvds/university

a81d20700a0ecf9560eb6c57ff38c2b5829a6645 — williamvds 5 years ago f6ec1e9
afp notes
1 files changed, 192 insertions(+), 0 deletions(-)

A afp/lectures.md
A afp/lectures.md => afp/lectures.md +192 -0
@@ 0,0 1,192 @@
# Functors

```haskell
class Functor f where
  fmap :: (a -> b) -> f a -> f b
```

## Examples

### Maybe

```haskell
instance Functor Maybe where
  -- fmap :: (a -> b) -> Maybe a -> Maybe b
  fmap _ Nothing  = Nothing
  fmap g (Just x) = Just (g x)
```

### Lists

```haskell
instance Functor [] where
  -- fmap :: (a -> b) -> [a] -> [b]
  fmap = map
```
- Applies a function to all elements

## Laws
```haskell
fmap id      = id
fmap (g . h) = fmap g . fmap h
```
- 1st: `fmap` preserves the identity function
- 2nd: `fmap` preserves function composition


# Applicative Functors
- Allow mapping a function with any number of arguments, rather than just ones
with a single argument

```haskell
class Functor f => Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b
```

## Examples 

### Maybe

```haskell
instance Applicative Maybe where
  -- pure :: a -> Maybe a
  pure = Just
  -- (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b
  Nothing  <*> _   = Nothing
  (Just g) <*> mx  = fmap g mx

> pure (+1) <*> Just 1
Just 2
> pure (+) <*> Just 1 <*> Just 2
Just 3
> pure (+) <*> Nothing <*> Just 2
Nothing
```
- Supports _exceptional_ programming - applying pure functions to arguments
which may fail

### Lists
```haskell
instance Applicative [] where
  -- pure :: a -> [a]
  pure x = [x]
  -- (<*>) :: [a -> b] -> [a] -> [b]
  gs <*> xs = [g x | g <- gs, x <- xs]

> pure (+1) <*> [1,2,3]
[2,3,4]
> pure (+) <*> [1] <*> [2]
[3]
> pure (*) <*> [1,2] <*> [3,4]
[3,4,6,8]
```
-- Applicative style for lists takes a list of functions and a list of
arguments, applying each in turn and returning a list of all results

## Laws

```haskell
pure id <*> x 	= x
pure (g x) 		  = pure g <*> pure x
x <*> pure y 	  = pure (\g -> g y) <*> x
x <*> (y <*> z) = (pure (.) <*> x <*> y) <*> z
```
- 1st: `pure` preserves the identity function - applying `pure` to it gives
an applicative version of it
- 2nd: `pure` preserves function application - it distributes over normal
function application to give applicative application
- 3rd: When an effectful function is applied to a pure argument, the order
in which the components are evaluated doesn't matter
- 4th: (Compensating for types) `<*>` is associative

# Monads
Comes from a branch of mathematics called _branch theory_.
```haskell
class Applicative m => Monad m where
  (>>=) :: m a -> (a -> m b) -> mb
  return :: a -> ma
  return = pure
```

## Examples

### Maybe
```haskell
instance Monad Maybe where
  -- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
  Nothing  >>= f = Nothing
  (Just x) >>= f = f x
```

### Lists
```haskell
instance Monad [] where
  -- (>>=) :: [a] -> (a -> [b]) -> [b]
  [] >>= f = []
  xs >>= f = concat $ map f xs -- (map f xs) :: [[b]], use concat to flatten
           = [y | x <- xs, y <- f x]

> pairs [1, 2] [3, 4]
[(1, 3), (1, 4), (2, 3), (2, 4)]

-- The cartesian product of two lists
pairs :: [a] -> [b] -> [(a, b)]
pairs xs ys = do x <- xs
                 y <- ys
                 return (x,y)
            = xs >>= \x ->
              ys >>= \y ->
              return (x, y)
-- similar to list comprehension [(x, y) | x <- xs, y <- ys]
```

List comprehensions are useful only to lists, whereas the do notation is general

### State
```haskell
type State = ...
type ST = State -> State -- state transformer: take current state and return new
type ST a = State -> (a, State) -- typed state transformer, of what is returned

Char -> ST Int
= Char -> State -> (Int, State)
-- ST abstracts away the state from the function type

type ST a = State -> (a, State)

-- Needs to be data in order to make a class definition
newtype ST a = S(State -> (a, State))

-- Get rid of 'dummy' constructor
app (S st) s = st s

-- TODO create functor and applicative

instance Monad ST where
  -- return :: a -> ST a
  return x = S (\s -> (x, s))
  -- s is the only State available, x is of type a

  -- (>>=) :: ST a -> (a -> ST b) -> ST b
  st >> f = S (\s -> let (x, s') = app st s
                     in app (f x) s')
  -- state transformer applied to s, returning value x and new state s'
  -- apply f to x and s', returning two new values (eg names y and s'')
```
## Laws
```haskell
return x >>= f = f x
mx >>= return  = mx
```
- Link between `return` and `>>=`
- 1st: `return`ing a value and feeding it into a monadic function = applying
the function to the value
- 2nd: Feeding the result of a monadic computation into `return` is the same
as performing the computation
- `return` is the identity for `>>=`

```haskell
(mx >>= f) >>= g = mx >>= (\x -> (f x >>= g))
```
- (Compensating for binding) `>>=` is associative