StateMonads

{-# LANGUAGE CPP #-}
module StateMonads where
import Control.Applicative
import Control.Monad(ap)
import Fudget(K) --,KEvent
import FudgetIO
import StreamProcIO
import EitherUtils(Cont(..))
import NullF(getK)

--------------------------------------------------------------------------------

-- | The continuation monad
newtype Mk k r = Mk {unMk::Cont k r}
-- | Continuation monad with unit result
type Mkc k = Mk k ()

instance Functor (Mk k) where
  fmap f (Mk m) = Mk (\k -> m (k.f))

instance Applicative (Mk k) where
  pure = return
  (<*>) = ap
  
instance Monad (Mk k) where
  return r =  Mk ($ r)
  Mk m1 >>= xm2 = Mk (m1 . flip (unMk . xm2))

--------------------------------------------------------------------------------

-- | Continuation monad with state (just an instance of the continuation monad)
type Ms k s r = Mk (s -> k) r
type Msc k s = Ms k s ()

loadMs  :: Ms k s s
storeMs :: s -> Msc k s
modMs   :: (s -> s) -> Msc k s
fieldMs :: (s -> f) -> Ms k s f

loadMs    = Mk (\ k s -> k s s)
storeMs s = Mk (\ k _ -> k () s)
modMs   f = Mk (\ k s -> k () (f s))
fieldMs r = Mk (\ k s -> k (r s) s)

nopMs :: Msc k s
nopMs = return ()

--------------------------------------------------------------------------------

toMkc :: (k -> k) -> Mkc k
toMkc k = Mk (\f -> k (f ()))

toMs :: Cont k r -> Ms k s r
toMs f = Mk (bmk f)
bmk f = (f .) . flip

toMsc :: (k -> k) -> Msc k r
toMsc k = Mk (\f -> k . f ())

--------------------------------------------------------------------------------
-- | Fudget Kernel Monad with State (just an instance...)
type Ks i o s ans = Ms (K i o) s ans
--type Ksc i o s = Ks i o s ()

{-
putsKs :: [KCommand a] -> Ksc b a c
putKs  :: KCommand a -> Ksc b a c
getKs  :: Ks a b c (KEvent a)
nullKs :: Ks i o s ()
loadKs :: Ks i o s s
storeKs :: s -> Ks i o s ()
-}
putHighsMs c = toMsc (puts c)
putHighMs  c = toMsc (put c)
putLowsMs  c = toMsc (putLows c)
putLowMs   c = toMsc (putLow c)
getKs        = toMs getK


-- Some synonyms, kept mostly for backwards compatibility
nullKs   =  nopMs
storeKs  = storeMs
loadKs   = loadMs
unitKs x = return x
bindKs m1 xm2 = m1>>=xm2
thenKs m1 m2 = m1>>m2
mapKs f = fmap f

-- Running a kernel monad

--stateMonadK :: s -> Ks i o s ans -> (ans -> K i o) -> K i o
stateMonadK s0 (Mk ks) k = ks (\ans state->k ans) s0

--stateK :: a -> (Ksc b c a) -> (K b c) -> K b c
stateK s (Mk ksc) k = ksc (const (const k)) s