module Control.Talk (
initialTalker
, tkApply
, Talker
, TalkM
, Message( .. )
, Answer( .. )
, runTalkMonad
, delegate
, getAnswer
) where
data Talker event container
= Talker {
tkEventbind :: [ Eventbind event container ] ,
tkContainerIndex :: Int ,
tkContainer :: [ container ]
}
data Message event container
= Wakeup | Goodnight | Howareyou | Event event | NoMessage |
PleaseAnswer ( Answer event container ) |
SupplyEventbind ( Answer event container )
( Eventbind event container ) |
Unbind ( Answer event container ) |
SetContainer ( Answer event container ) container |
GetContainer ( Message event container ) |
ModifyContainer ( Answer event container )
( container -> container ) |
CopyContainer ( Answer event container ) |
RemoveContainer ( Answer event container )
data Answer event container
= GivemeEventbind | GivemeEvent | Asleep | Awake | NoAnswer |
ContainerIs ( Message event container ) container
data TalkM t a =
Terminus { runTerminus :: [ TalkM t () ] -> t -> ( a, t ) } | Delegate
putActions :: [ TalkM t () ] -> TalkM t a -> TalkM t a
putActions tms ( Terminus x ) = Terminus $ \_ -> x tms
putActions _ Delegate = Delegate
delegate :: TalkM t ()
delegate = Terminus $ \( tm : tms ) t -> runTerminus tm tms t
instance Monad ( TalkM t ) where
return a = Terminus $ \_ t -> ( a, t )
Terminus x >>= f = Terminus $ \tms t ->
let ( v, t' ) = x tms t
in case f v of
Delegate -> ( error "not allow delegate here", t' )
term -> runTerminus term tms t'
Delegate >>= _ = Delegate
type Eventbind event container =
Message event container ->
TalkM ( Talker event container, Answer event container ) ()
runTalkMonad ::
TalkM ( Talker e c, Answer e c ) a -> Talker e c -> ( Answer e c, Talker e c )
runTalkMonad term t = flipTuple $ snd $ runTerminus term [ ] ( t, NoAnswer )
where
flipTuple ( x, y ) = ( y, x )
put :: t -> TalkM ( t, Answer e c ) ()
put t = Terminus $ \_ ( _, a ) -> ( (), ( t, a ) )
get :: TalkM ( t, Answer e c ) t
get = Terminus $ \_ ( t, a ) -> ( t , ( t, a ) )
putAnswer :: Answer e c -> TalkM ( t, Answer e c ) ()
putAnswer a = Terminus $ \_ ( t, _ ) -> ( (), ( t, a ) )
getAnswer :: TalkM ( t, Answer e c ) ( Answer e c )
getAnswer = Terminus $ \_ ( t, a ) -> ( a , ( t, a ) )
initialTalker :: Talker event container
initialTalker = Talker {
tkEventbind = [ initialEventbind ] ,
tkContainerIndex = 0 ,
tkContainer = [ ]
}
initialEventbind, howareyouEventbind :: Eventbind e c
howareyouEventbind Howareyou = putAnswer Awake
howareyouEventbind _ = delegate
initialEventbind Howareyou = putAnswer Asleep
initialEventbind Wakeup = do
tk@Talker { tkEventbind = eventbinds } <- get
put tk { tkEventbind = howareyouEventbind : eventbinds }
putAnswer GivemeEventbind
initialEventbind Goodnight = do
tk <- get
put tk { tkEventbind = [ initialEventbind ] }
putAnswer Asleep
initialEventbind ( PleaseAnswer answer ) =
putAnswer answer
initialEventbind ( SupplyEventbind answer eventbind ) = do
tk@Talker { tkEventbind = eventbinds } <- get
put tk { tkEventbind = eventbind : eventbinds }
putAnswer answer
initialEventbind ( Unbind answer ) = do
tk@Talker { tkEventbind = _ : eventbinds } <- get
put tk { tkEventbind = eventbinds }
putAnswer answer
initialEventbind ( SetContainer answer val ) = do
tk@Talker { tkContainerIndex = i, tkContainer = vals } <- get
put tk { tkContainer = take i vals ++ [ val ] ++ drop ( i + 1 ) vals }
putAnswer answer
initialEventbind ( GetContainer msg ) = do
Talker { tkContainerIndex = i, tkContainer = vals } <- get
if i > 1 && i < length vals
then putAnswer $ ContainerIs msg ( vals !! i )
else error "not occur"
initialEventbind ( ModifyContainer answer m ) = do
tk@Talker { tkContainerIndex = i, tkContainer = vals } <- get
put tk { tkContainer = take i vals ++ [ m $ vals !! i ] ++ drop ( i + 1 ) vals }
putAnswer answer
initialEventbind ( CopyContainer answer ) = do
tk@Talker { tkContainerIndex = i, tkContainer = vals } <- get
if i < 0 then error "not occur in CopyContainer" else do
put tk { tkContainerIndex = 0, tkContainer = vals !! i : vals }
putAnswer answer
initialEventbind ( RemoveContainer answer ) = do
tk@Talker { tkContainerIndex = i, tkContainer = vals } <- get
if length vals <= 1
then tkApply Goodnight
else do
put tk { tkContainerIndex = if i < length vals 1 then i else i 1 ,
tkContainer = take i vals ++ drop ( i + 1 ) vals }
putAnswer answer
initialEventbind _ = error "not bind"
tkApply :: Eventbind e c
tkApply msg = do
tk@Talker { tkEventbind = eventbinds } <- get
apply eventbinds tk
where
apply [ ] _ = error "no event bind in tkApply"
apply ( eb : ebs ) tk = case eb msg of
Delegate -> apply ebs tk
term -> putActions ( map ($ msg) ebs ) term