module Acme.TimeMachine.Undoable (
Suspension,
Undoable(..),
evalUndoable,
execUndoable,
suspend,
resume,
undo
)
where
import Control.Applicative (Applicative(..))
import Control.Monad.State.Class (MonadState(..))
import Acme.TimeMachine.Suspension
data Undoable s a = Undoable { getUndoable :: Suspension s -> (Suspension s, a) }
runUndoable :: Undoable s a -> s -> (s, a)
runUndoable (Undoable f) s = case f (mkSuspension s) of ~(Suspension s _, r) -> (s, r)
evalUndoable :: Undoable s a -> s -> a
evalUndoable (Undoable f) s = case f (mkSuspension s) of ~(_, r) -> r
execUndoable :: Undoable s a -> s -> s
execUndoable (Undoable f) s = case f (mkSuspension s) of ~(Suspension s _, _) -> s
suspend :: Undoable s (Suspension s)
suspend = Undoable $ \l -> (l, l)
resume :: Suspension s -> Undoable s ()
resume l = Undoable $ \_ -> (l, ())
undo :: Undoable s ()
undo = Undoable $ \(Suspension _ l) -> (l, ())
instance Functor (Undoable s) where
fmap f (Undoable x) = Undoable $ \l -> case x l of ~(l, r) -> (l, f r)
instance Applicative (Undoable s) where
pure x = Undoable $ \l -> (l, x)
(Undoable f) <*> (Undoable k) = Undoable $ \l -> case f l of ~(l, f) -> case k l of ~(l, k) -> (l, f k)
instance Monad (Undoable s) where
return x = Undoable $ \l -> (l, x)
(Undoable k) >>= f = Undoable $ \l -> case k l of ~(l, r) -> getUndoable (f r) l
(Undoable k) >> (Undoable f) = Undoable $ \l -> case k l of ~(l, _) -> f l
instance MonadState s (Undoable s) where
get = Undoable $ \l@(Suspension s _) -> (l, s)
put s = Undoable $ \l -> (Suspension s l, ())