ReactionM

{-# LANGUAGE CPP #-}
module ReactionM where
import Data.Maybe(isJust)
import Control.Applicative
import Control.Monad(ap)

-- | Writer & State & Exception monad
newtype ReactionM s o a = M (s -> [o] -> Maybe (s,[o],a))

instance Functor (ReactionM s o) where
  fmap f m = do x <- m; return (f x)

instance Applicative (ReactionM s o) where
  pure = return
  (<*>) = ap

instance Monad (ReactionM s o) where
  return x = M (\s o->Just (s,o,x))
  (M f1) >>= xm2 =
    M $ \ s0 o0 ->
      let r1 = f1 s0 o2
          Just (s1,o1,x1) = r1
          M f2 = xm2 x1
	  r2 = f2 s1 o0
	  Just (s2,o2,x2) = r2
      in if isJust r1 && isJust r2
         then Just (s2,o1,x2)
	 else Nothing
  fail _ = rfail

react (M f) s0 = case f s0 [] of Just (s,o,_) -> (s,o); _ -> (s0,[])
put o = M $ \ s os -> Just (s,o:os,())
set s = M $ \ _ os -> Just (s,os,())
get = M $ \ s os -> Just (s,os,s)
field f = f <$> get
update f = M $ \ s os -> Just (f s,os,())

rfail = M $ \ _ _ -> Nothing

lift m = maybe rfail return m
nop = return ()
nop :: Monad m => m ()