{-# LANGUAGE Arrows #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TupleSections #-} {- I implemented State and Reader arrows (actually as Arrow Transformers) for educational purposes in order to understand arrows better. Never use this code in a production environment. State and Reader arrows have already been defined. I reimplemented them purely for educational purposes. -} module Educational where import Prelude hiding ((.), id) import Control.Arrow import Control.Category import qualified Data.Bifunctor as Bi newtype Identity b c = Identity { runIdentity :: b -> c } instance Category Identity where id = arr id (Identity c) . (Identity b) = Identity $ c . b instance Arrow Identity where arr = Identity first (Identity b) = Identity $ Bi.first b second (Identity b) = Identity $ Bi.second b class ArrowTrans t where lift :: (Arrow a) => a b c -> t a b c newtype StateT s a b c = StateT { runStateT :: a (b, s) (c, s) } instance Category a => Category (StateT s a) where id = StateT id (StateT c) . (StateT b) = StateT $ c . b instance Arrow a => Arrow (StateT s a) where arr = StateT . first . arr first (StateT f) = StateT $ arr (\((b, d), s) -> ((b, s), d)) >>> first f >>> arr (\((c, s), d) -> ((c, d), s)) second (StateT f) = StateT $ arr (\((d, b), s) -> (d, (b, s))) >>> second f >>> arr (\(d, (c, s)) -> ((d, c), s)) class Arrow a => ArrowState s a | a -> s where gets :: a () s puts :: a s s modify :: (s -> s) -> a () s instance Arrow a => ArrowState s (StateT s a) where gets = StateT $ arr $ \(_, s) -> (s, s) puts = StateT $ arr $ \(s, _) -> (s, s) modify t = StateT $ arr $ \(_, s) -> let s' = t s in (s', s') instance ArrowTrans (StateT s) where lift = StateT . first type State s b c = StateT s Identity b c runState = runIdentity . runStateT newtype ReaderT r a b c = ReaderT { runReaderT :: r -> a b c } instance Category a => Category (ReaderT r a) where id = ReaderT $ const id (ReaderT c) . (ReaderT b) = ReaderT $ \r -> c r . b r instance Arrow a => Arrow (ReaderT r a) where arr = ReaderT . const . arr first (ReaderT f) = ReaderT $ first . f second (ReaderT f) = ReaderT $ second . f class Arrow a => ArrowReader r a | a -> r where ask :: a () r instance Arrow a => ArrowReader r (ReaderT r a) where ask = ReaderT $ arr . const instance ArrowTrans (ReaderT r) where lift = ReaderT . const type Reader r b c = ReaderT r Identity b c runReader :: Reader r b c -> r -> b -> c runReader a r = runIdentity (runReaderT a r) zoo :: ArrowReader Int a => a Int Int zoo = arr ((),) >>> first ask >>> arr (uncurry (*)) foo :: ArrowState Int a => a Int Int foo = arr ((),) >>> first (modify (+3)) >>> second (arr (*2)) >>> arr (uncurry (+)) someFunc :: IO () someFunc = print $ runState foo (7, 9)