hans-2.1.0.0: src/Hans/Layer.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Rank2Types #-}
module Hans.Layer where
import Hans.Utils (just)
import Control.Applicative (Applicative(..),Alternative(..))
import Control.Monad (ap,MonadPlus(mzero,mplus))
import Data.Monoid (Monoid(..))
import Data.Time.Clock.POSIX
import MonadLib (StateM(get,set))
import qualified Control.Exception as X
import qualified Data.Map as Map
data LayerState i = LayerState
{ lsNow :: POSIXTime
, lsState :: i
}
data Action = Nop | Action (IO ())
instance Monoid Action where
mempty = Nop
mappend (Action a) (Action b) = Action (a >> b)
mappend Nop b = b
mappend a _ = a
runAction :: Action -> IO ()
runAction Nop = return ()
runAction (Action m) = m `X.catch` \ se -> print (se :: X.SomeException)
data Result i a
= Error Action
| Result (LayerState i) a Action
-- | Failure continuation
type Failure i r = Action -> Result i r
-- | Success continuation
type Success a i r = a -> LayerState i -> Action -> Result i r
newtype Layer i a = Layer
{ getLayer :: forall r. LayerState i -> Action
-> Failure i r -> Success a i r
-> Result i r }
runLayer :: LayerState i -> Layer i a -> Result i a
runLayer i0 m = getLayer m i0 mempty Error success
where success a i o = Result i a o
loopLayer :: i -> IO msg -> (msg -> Layer i ()) -> IO ()
loopLayer i0 msg k = loop (LayerState 0 i0)
where
loop i = do
a <- msg
now <- getPOSIXTime
let res = runLayer (i {lsNow = now }) (k a)
X.evaluate res `X.catch` \ se -> print (se :: X.SomeException) >> return res
case res of
Error m -> runAction m >> loop i
Result i' () m -> runAction m >> loop i'
instance Functor (Layer i) where
fmap g m = Layer (\i0 o0 f k -> getLayer m i0 o0 f (\a i o -> k (g a) i o))
instance Applicative (Layer i) where
pure = return
(<*>) = ap
instance Alternative (Layer i) where
empty = Layer (\_ o0 f _ -> f o0)
a <|> b = Layer (\i o f k -> getLayer a i o (\_ -> getLayer b i o f k) k)
instance Monad (Layer i) where
return x = Layer (\i o _ k -> k x i o)
m >>= g = Layer $ \i0 o0 f k -> getLayer m i0 o0 f $ \a i o ->
getLayer (g a) i o f k
instance MonadPlus (Layer i) where
mzero = empty
mplus = (<|>)
instance StateM (Layer i) i where
get = Layer (\i0 o0 _ k -> k (lsState i0) i0 o0)
set i = Layer (\i0 o0 _ k -> k () (i0 { lsState = i }) o0)
-- Utilities -------------------------------------------------------------------
dropPacket :: Layer i a
dropPacket = empty
time :: Layer i POSIXTime
time = Layer $ \i0 o0 _ k -> k (lsNow i0) i0 o0
output :: IO () -> Layer i ()
output m = Layer $ \i0 o0 _ k -> k () i0 (o0 `mappend` Action m)
liftRight :: Either String b -> Layer i b
liftRight (Right b) = return b
liftRight (Left err) = do
output (putStrLn err)
dropPacket
-- Handler Generalization ------------------------------------------------------
type Handlers k a = Map.Map k a
emptyHandlers :: Handlers k a
emptyHandlers = Map.empty
class ProvidesHandlers i k a | i -> k a where
getHandlers :: i -> Handlers k a
setHandlers :: Handlers k a -> i -> i
getHandler :: (Ord k, ProvidesHandlers i k a) => k -> Layer i a
getHandler k = do
state <- get
just (Map.lookup k (getHandlers state))
addHandler :: (Ord k, ProvidesHandlers i k a) => k -> a -> Layer i ()
addHandler k a = do
state <- get
let hs' = Map.insert k a (getHandlers state)
hs' `seq` set (setHandlers hs' state)
removeHandler :: (Ord k, ProvidesHandlers i k a) => k -> Layer i ()
removeHandler k = do
state <- get
let hs' = Map.delete k (getHandlers state)
hs' `seq` set (setHandlers hs' state)