> module Week1403 where
> import Control.Monad
* Arrows - Motivation
This lecture is based on John Hughes's arrow tutorial
Programming With Arrows
http://www.cse.chalmers.se/~rjmh/afp-arrows.pdf
Many Haskell programmers enjoy point-free definition like this one, which counts the number of occurrences of a word in a string.
> count w = length . filter (==w) . words
However, the corresponding program to count the words in a file cannot easily be written in a point-free style. In particular, the following does not type check:
| countFile w = print . length . filter (==w) . words . readFile
... because readFile and print are in the IO monad.
A Little bit of combinator gymnastics helps:
> countFile w = (>>= print) . liftM (length . filter (==w) . words) . readFile
But there is a better approach. Let's define the type of arrows in the Kleisli category over a monad.
> type Kleisli m a b = a -> m b
With this definition, we can see that readFile and print are both Kleisli arrows.
| readFile :: Kleisli IO String String
| print :: Show a => Kleisli IO a ()
Next, define Kleisli composition:
> (>>>) :: (Functor m, Monad m) => Kleisli m a b -> Kleisli m b c -> Kleisli m a c
> -- (f >>> g) a = f a >>= g
> f >>> g = join . fmap g . f
> printFile = readFile >>> print
... but in the original problem, there were also effect-free functions that needed to be composed with the Kleisli arrows. Solution: we lift standard arrows to Kleisli arrows.
> arr :: Monad m => (a -> b) -> Kleisli m a b
> arr f = return . f
Now, we can give a convenient point-free definition:
> countK w = readFile >>> arr words >>> arr (filter (==w)) >>> arr length >>> print