# Arrows, …

… Monads, Profunctors, Categories, Applicatives, and everything else.

# (Pro)functors

## Functors

``````class Functor f where
fmap
::  (a ->   b)
-> f a -> f b``````
``````data Stream a = Stream a (Stream a)

head (Stream a _) = a``````
``````instance Functor Stream where
fmap f (Stream a as) = Stream (f a) \$ fmap f as``````

## Stream functions

`Stream a -> Stream b` subtype hierarchy:

• `a -> b` (via `fmap`)
• `a -> Stream b` (via e.g. `head`)
• Synchronous stream functions (`SF`)
• Arbitrary functions `Stream a -> Stream b`
``````newtype SF a b = SF (a -> (b, SF a b))

apply :: SF a           b
-> Stream a -> Stream b
apply (SF unSF) (Stream a as) = let (b, sf') = unSF a
in Stream b \$ apply sf' as``````

## Functor

``````instance Functor ((->) a) where
fmap = (.)

newtype Kleisli f a b = Kleisli (a -> f b)
instance Functor (Kleisli Stream a) where
fmap f (Kleisli k) = Kleisli \$ fmap f . k

instance Functor (SF a) where
fmap f (SF unSF) = SF \$ \a ->
let (b, sf') = unSF a in (f b, fmap f sf')``````

## Profunctor

But we can also precompose with functions! (A.k.a `Contravariant`.)

``````class Profunctor p where
lmap ::  (a -> b)
-> p      b    c
-> p a         c
rmap ::       (b -> c)
-> p a    b
-> p a         c``````
``````instance Profunctor (->) where
lmap = flip (.)
rmap = (.) -- This is just fmap!``````

## (Pro)functor

• Every functor `f` gives several canonical profunctors:
• `a -> f b` (Kleisli)
• `f a -> b` (Cokleisli, irrelevant today)
• `f a -> f b`
• Instances are all cobbled together with `(.)` and `fmap`.
• But there are profunctors that are not of this form!
``````instance Profunctor SF where
rmap = fmap
lmap f (SF unSF) = SF \$ \a ->
let (c, sf') = unSF \$ f a in (c, lmap f sf')``````

## Functor < Profunctor?

• Every `Profunctor` gives you back a `Functor`..
• …by fixing the “input” type
• Just use `rmap`
• But you cannot always recover the `Profunctor` from that!
• Example: `SF`

# Arrows

## Applicative < Arrow < Monad?

In the `Functor`-`Applicative`-`Monad`-hierarchy, people sometimes insert `Arrow`.

``````-- Note: I'm leaving out 'Category' for simplicity
class Arrow arr where
arr ::    (a -> b)
-> arr a    b
(&&&) :: arr a  b
-> arr a     c
-> arr a (b, c)
(>>>) :: arr a  b
-> arr    b  c
-> arr a     c``````

## Profunctor < Arrow!

• `arr` and `(>>>)` generalise `lmap` and `rmap`.

• Every monad `m` gives several canonical arrows:
• `a -> m b` (Kleisli)
• `m a -> b` (Cokleisli, irrelevant today)
• `m a -> m b`
• Instances are all cobbled together with `(.)` and `fmap`.
• But there are arrows that are not of this form!
``````instance Arrow SF where
-- Exercises for you``````

## Applicative < Arrow?

• Every `Arrow` gives you back an `Applicative`
• …by fixing the “input” type
• Just use (`&&&)`
• But you cannot always recover the `Arrow` from that!
• Example: `SF`