> module Part1 where > import Monad > infixr 3 *** > infixr 3 &&& > infixr 2 +++ > infixr 2 ||| > infixr 1 >>> > infixr 9 .*. Notions of computation > add :: (b -> Int) -> (b -> Int) -> b -> Int > add f g b = f b + g b Adding the results of two state transformers > type StateTrans'1 s b c = (s,b) -> (s,c) > addST :: StateTrans'1 s b Int -> StateTrans'1 s b Int -> > StateTrans'1 s b Int > addST f g (s,b) = let (s', x) = f (s, b) > (s'', y) = g (s', b) > in (s'', x+y) Backtracking > type Backtrack'1 b c = b -> [c] > addBT :: Backtrack'1 b Int -> Backtrack'1 b Int -> > Backtrack'1 b Int > addBT f g b = [x+y | x <- f b, y <- g b] > addBT'1 f g b = > concat (map (\x -> map (\y -> x+y) (g b)) (f b)) Stream processors > type StreamProc'1 b c = [b] -> [c] > addSP :: StreamProc'1 b Int -> StreamProc'1 b Int -> > StreamProc'1 b Int > addSP f g bs = map (\(x,y) -> (x+y)) (zip (f bs) (g bs)) The arrow class > class Arrow a where > pure :: (b -> c) -> a b c > (>>>) :: a b c -> a c d -> a b d > first :: a b c -> a (b,d) (c,d) There is no need to assume second > second :: Arrow a => a b c -> a (d,b) (d,c) > second f = pure swap >>> first f >>> pure swap > where swap ~(x,y) = (y,x) Some instances > instance Arrow (->) where > pure f = f > f >>> g = g . f > first f (x,y) = (f x, y) > newtype StateTrans s b c = ST ((s,b) -> (s,c)) > fetch :: StateTrans s b s > fetch = ST (\(s,_) -> (s,s)) > store :: StateTrans s s () > store = ST (\(_,s) -> (s,())) > instance Arrow (StateTrans s) where > pure f = ST (\(s, b) -> (s, f b)) > ST f >>> ST g = ST (g . f) > first (ST f) = ST (\(s, (b,d)) -> > let (s', c) = f (s, b) > in (s', (c, d))) Backtracking > newtype Backtrack b c = BT (b -> [c]) > instance Arrow Backtrack where > pure f = BT (\b -> [f b]) > BT f >>> BT g = BT (\b -> [y | x <- f b, y <- g x]) > first (BT f) = BT (\(b,d) -> [(c, d) | c <- f b]) Stream processors > newtype StreamProc b c = SP ([b] -> [c]) > instance Arrow StreamProc where > pure f = SP (map f) > SP f >>> SP g = SP (g . f) > first (SP f) = SP (\bds -> > zip (f (map fst bds)) (map snd bds)) > delay :: b -> StreamProc b b > delay b = SP (b:) General add combinators > addA :: Arrow a => a b Int -> a b Int -> a b Int > addA f g = pure (\b -> (b,b)) >>> > first f >>> second g >>> pure (\(x,y) -> x+y) > addA' :: Arrow a => a b Int -> a b Int -> a b Int > addA' f g = pure (\b -> (b,b)) >>> > second g >>> first f >>> pure (\(x,y) -> x+y) Derived combinators > (***) :: Arrow a => a b c -> a b' c' -> a (b,b') (c,c') > f *** g = first f >>> second g > (&&&) :: Arrow a => a b c -> a b c' -> a b (c,c') > f &&& g = pure (\b -> (b,b)) >>> f *** g > addA'1 f g = f &&& g >>> pure (\(x,y) -> x+y) Static properties > data Count a b c = Count Int (a b c) > instance Arrow a => Arrow (Count a) where > pure f = Count 0 (pure f) > Count n1 f1 >>> Count n2 f2 = > Count (n1+n2) (f1 >>> f2) > first (Count n f) = Count n (first f) Axioms of first > (.*.) :: (a -> a') -> (b -> b') -> (a,b) -> (a',b') > (f .*. g) (a,b) = (f a, g b) Elimination and associativity > assoc :: ((a,b),c) -> (a,(b,c)) > assoc ((a,b),c) = (a,(b,c)) Output as an arrow > newtype Writer b c = W (b -> (String, c)) > write :: Show b => Writer b () > write = W (\b -> (show b, ())) > instance Arrow Writer where > pure f = W (\b -> ([], f b)) > W f >>> W g = W (\b -> > let (s1, c) = f b > (s2, d) = g c > in (s1++s2, d)) > first (W f) = W (\(b,d) -> > let (s, c) = f b > in (s, (c,d))) Map transformers > newtype MapTrans s b c = MT ((s -> b) -> (s -> c)) > instance Arrow (MapTrans s) where > pure f = MT (\h -> f . h) > MT f >>> MT g = MT (g . f) > first (MT f) = MT (\h s -> (f (fst . h) s, snd (h s))) Continuation-passing style > newtype CPS r b c = CPS ((c -> r) -> (b -> r)) > instance Arrow (CPS r) where > pure f = CPS (\k -> k . f) > CPS f >>> CPS g = CPS (f . g) > first (CPS f) = CPS (\k -> \(b,d) -> f (\c -> k (c,d)) b) Simple automata > newtype Auto b c = A (b -> (c, Auto b c)) > instance Arrow Auto where > pure f = A (\b -> (f b, pure f)) > A f >>> A g = A (\b -> let (c, f') = f b > (d, g') = g c > in (d, f' >>> g')) > first (A f) = A (\(b,d) -> let (c, f') = f b > in ((c,d), first f')) > delay'1 :: b -> Auto b b > delay'1 b = A (\b' -> (b, delay'1 b')) Conditionals > class Arrow a => ArrowChoice a where > left :: a b c -> a (Either b d) (Either c d) > instance ArrowChoice (->) where > left f (Left x) = Left (f x) > left f (Right y) = Right y > instance ArrowChoice (StateTrans s) where > left (ST f) = ST (\(s,x) -> case x of > Left b -> let (s', c) = f (s,b) > in (s', Left c) > Right d -> (s, Right d)) Auxilliary definitions > right :: ArrowChoice a => a b c -> a (Either d b) (Either d c) > right f = pure mirror >>> left f >>> pure mirror > where mirror (Left x) = Right x > mirror (Right y) = Left y > (+++) :: ArrowChoice a => a b c -> a b' c' -> > a (Either b b') (Either c c') > f +++ g = left f >>> right g > (|||) :: ArrowChoice a => a b d -> a c d -> a (Either b c) d > f ||| g = f +++ g >>> pure untag > where untag (Left x) = x > untag (Right y) = y ArrowChoice instances > instance ArrowChoice Backtrack where > left (BT f) = BT (\x -> case x of > Left b -> map Left (f b) > Right d -> [Right d]) > instance ArrowChoice a => ArrowChoice (Count a) where > left (Count n f) = Count n (left f) > instance ArrowChoice Auto where > left (A f) = A (\x -> case x of > Left b -> let (c, f') = f b > in (Left c, left f') > Right d -> (Right d, left (A f))) Next week: arrow notation > prodA f g = pure (\(s,(x,y)) -> ((s,x),y)) >>> first f >>> > pure (\((s',x'),y) -> ((s',y),x')) >>> first g >>> > pure (\((s'',y'),x') -> (s'',(x',y'))) Hyper-functions > newtype Hyper b c = H (Hyper c b -> c) > instance Arrow Hyper where > pure f = H (\(H k) -> f (k (pure f))) > f >>> H g = H (\k -> g (k >>> f)) > first (H f) = H (\(H k) -> > (f (H (\k' -> fst (k (first k')))), > snd (k (first (H f)))))