module Web.Routes.RouteT where
import Control.Applicative (Applicative((<*>), pure), Alternative((<|>), empty))
import Control.Monad (MonadPlus(mzero, mplus))
import Control.Monad.Catch (MonadCatch(catch), MonadThrow(throwM))
import Control.Monad.Cont(MonadCont(callCC))
import Control.Monad.Error (MonadError(throwError, catchError))
import Control.Monad.Fix (MonadFix(mfix))
import Control.Monad.Reader(MonadReader(ask,local))
import Control.Monad.RWS (MonadRWS)
import Control.Monad.State(MonadState(get,put))
import Control.Monad.Trans (MonadTrans(lift), MonadIO(liftIO))
import Control.Monad.Writer(MonadWriter(listen, tell, pass))
import Data.Text (Text)
newtype RouteT url m a = RouteT { unRouteT :: (url -> [(Text, Maybe Text)] -> Text) -> m a }
class (Monad m) => MonadRoute m where
type URL m
askRouteFn :: m (URL m -> [(Text, Maybe Text)] -> Text)
instance MonadCatch m => MonadCatch (RouteT url m) where
catch action handler =
RouteT $ \ fn -> catch (action' fn) (\ e -> handler' e fn)
where
action' = unRouteT action
handler' e = unRouteT (handler e)
instance MonadThrow m => MonadThrow (RouteT url m) where
throwM = throwM'
where
throwM' e = RouteT $ \ _fn -> throwM e
runRouteT :: (url -> RouteT url m a)
-> ((url -> [(Text, Maybe Text)] -> Text) -> url -> m a)
runRouteT r = \f u -> (unRouteT (r u)) f
mapRouteT :: (m a -> n b) -> RouteT url m a -> RouteT url n b
mapRouteT f (RouteT m) = RouteT $ f . m
withRouteT :: ((url' -> [(Text, Maybe Text)] -> Text) -> (url -> [(Text, Maybe Text)] -> Text)) -> RouteT url m a -> RouteT url' m a
withRouteT f (RouteT m) = RouteT $ m . f
liftRouteT :: m a -> RouteT url m a
liftRouteT m = RouteT (const m)
askRouteT :: (Monad m) => RouteT url m (url -> [(Text, Maybe Text)] -> Text)
askRouteT = RouteT return
instance (Functor m) => Functor (RouteT url m) where
fmap f = mapRouteT (fmap f)
instance (Applicative m) => Applicative (RouteT url m) where
pure = liftRouteT . pure
f <*> v = RouteT $ \ url -> unRouteT f url <*> unRouteT v url
instance (Alternative m) => Alternative (RouteT url m) where
empty = liftRouteT empty
m <|> n = RouteT $ \ url -> unRouteT m url <|> unRouteT n url
instance (Monad m) => Monad (RouteT url m) where
return = liftRouteT . return
m >>= k = RouteT $ \ url -> do
a <- unRouteT m url
unRouteT (k a) url
fail msg = liftRouteT (fail msg)
instance (MonadPlus m, Monad (RouteT url m)) => MonadPlus (RouteT url m) where
mzero = liftRouteT mzero
m `mplus` n = RouteT $ \ url -> unRouteT m url `mplus` unRouteT n url
instance (MonadCont m) => MonadCont (RouteT url m) where
callCC f = RouteT $ \url ->
callCC $ \c ->
unRouteT (f (\a -> RouteT $ \_ -> c a)) url
instance (MonadError e m) => MonadError e (RouteT url m) where
throwError = liftRouteT . throwError
catchError action handler = RouteT $ \f -> catchError (unRouteT action f) (\e -> unRouteT (handler e) f)
instance (MonadFix m) => MonadFix (RouteT url m) where
mfix f = RouteT $ \ url -> mfix $ \ a -> unRouteT (f a) url
instance (MonadIO m) => MonadIO (RouteT url m) where
liftIO = lift . liftIO
instance (MonadReader r m) => MonadReader r (RouteT url m) where
ask = liftRouteT ask
local f = mapRouteT (local f)
instance (MonadRWS r w s m) => MonadRWS r w s (RouteT url m)
instance (MonadState s m) => MonadState s (RouteT url m) where
get = liftRouteT get
put s = liftRouteT $ put s
instance MonadTrans (RouteT url) where
lift = liftRouteT
instance (MonadWriter w m) => MonadWriter w (RouteT url m) where
tell w = liftRouteT $ tell w
listen m = mapRouteT listen m
pass m = mapRouteT pass m
instance (Monad m) => MonadRoute (RouteT url m) where
type URL (RouteT url m) = url
askRouteFn = askRouteT
showURL :: (MonadRoute m) => URL m -> m Text
showURL url =
do showFn <- askRouteFn
return (showFn url [])
showURLParams :: (MonadRoute m) => URL m -> [(Text, Maybe Text)] -> m Text
showURLParams url params =
do showFn <- askRouteFn
return (showFn url params)
nestURL :: (url1 -> url2) -> RouteT url1 m a -> RouteT url2 m a
nestURL transform (RouteT r) =
do RouteT $ \showFn ->
r (\url params -> showFn (transform url) params)