\begin{comment}
\begin{code}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StandaloneDeriving #-}
module LiveCoding.Debugger where
import Control.Concurrent
import Control.Monad (void)
import Data.Data
import Data.IORef
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.State.Strict
import Data.Generics.Text
import LiveCoding.LiveProgram
import LiveCoding.Cell
\end{code}
\end{comment}
\subsection{Debugging the Live State}
Having the complete state of the program in one place allows us to inspect and debug it in a central place.
We might want to interact with the user,
display aspects of the state
and possibly even change it in place.
In short, a debugger is a program that can read and modify,
as an additional effect,
the state of an arbitrary live program:
\begin{code}
newtype Debugger m = Debugger
{ Debugger m -> forall s. Data s => LiveProgram (StateT s m)
getDebugger :: forall s .
Data s => LiveProgram (StateT s m)
}
\end{code}
\begin{comment}
\begin{code}
instance Monad m => Semigroup (Debugger m) where
Debugger m
debugger1 <> :: Debugger m -> Debugger m -> Debugger m
<> Debugger m
debugger2 = (forall s. Data s => LiveProgram (StateT s m)) -> Debugger m
forall (m :: * -> *).
(forall s. Data s => LiveProgram (StateT s m)) -> Debugger m
Debugger ((forall s. Data s => LiveProgram (StateT s m)) -> Debugger m)
-> (forall s. Data s => LiveProgram (StateT s m)) -> Debugger m
forall a b. (a -> b) -> a -> b
$ Debugger m -> forall s. Data s => LiveProgram (StateT s m)
forall (m :: * -> *).
Debugger m -> forall s. Data s => LiveProgram (StateT s m)
getDebugger Debugger m
debugger1 LiveProgram (StateT s m)
-> LiveProgram (StateT s m) -> LiveProgram (StateT s m)
forall a. Semigroup a => a -> a -> a
<> Debugger m -> forall s. Data s => LiveProgram (StateT s m)
forall (m :: * -> *).
Debugger m -> forall s. Data s => LiveProgram (StateT s m)
getDebugger Debugger m
debugger2
instance Monad m => Monoid (Debugger m) where
mempty :: Debugger m
mempty = (forall s. Data s => LiveProgram (StateT s m)) -> Debugger m
forall (m :: * -> *).
(forall s. Data s => LiveProgram (StateT s m)) -> Debugger m
Debugger forall s. Data s => LiveProgram (StateT s m)
forall a. Monoid a => a
mempty
getC :: Monad m => Cell (StateT s m) a s
getC :: Cell (StateT s m) a s
getC = StateT s m s -> Cell (StateT s m) a s
forall (m :: * -> *) b a. m b -> Cell m a b
constM StateT s m s
forall (m :: * -> *) s. Monad m => StateT s m s
get
putC :: Monad m => Cell (StateT s m) s ()
putC :: Cell (StateT s m) s ()
putC = (s -> StateT s m ()) -> Cell (StateT s m) s ()
forall a (m :: * -> *) b. (a -> m b) -> Cell m a b
arrM s -> StateT s m ()
forall (m :: * -> *) s. Monad m => s -> StateT s m ()
put
\end{code}
\end{comment}
A simple debugger prints the unmodified state to the console:
\begin{code}
gshowDebugger :: Debugger IO
gshowDebugger :: Debugger IO
gshowDebugger = (forall s. Data s => LiveProgram (StateT s IO)) -> Debugger IO
forall (m :: * -> *).
(forall s. Data s => LiveProgram (StateT s m)) -> Debugger m
Debugger
((forall s. Data s => LiveProgram (StateT s IO)) -> Debugger IO)
-> (forall s. Data s => LiveProgram (StateT s IO)) -> Debugger IO
forall a b. (a -> b) -> a -> b
$ Cell (StateT s IO) () () -> LiveProgram (StateT s IO)
forall (m :: * -> *). Monad m => Cell m () () -> LiveProgram m
liveCell (Cell (StateT s IO) () () -> LiveProgram (StateT s IO))
-> Cell (StateT s IO) () () -> LiveProgram (StateT s IO)
forall a b. (a -> b) -> a -> b
$ (() -> StateT s IO ()) -> Cell (StateT s IO) () ()
forall a (m :: * -> *) b. (a -> m b) -> Cell m a b
arrM ((() -> StateT s IO ()) -> Cell (StateT s IO) () ())
-> (() -> StateT s IO ()) -> Cell (StateT s IO) () ()
forall a b. (a -> b) -> a -> b
$ StateT s IO () -> () -> StateT s IO ()
forall a b. a -> b -> a
const (StateT s IO () -> () -> StateT s IO ())
-> StateT s IO () -> () -> StateT s IO ()
forall a b. (a -> b) -> a -> b
$ do
s
state <- StateT s IO s
forall (m :: * -> *) s. Monad m => StateT s m s
get
IO () -> StateT s IO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> StateT s IO ()) -> IO () -> StateT s IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ s -> String
forall a. Data a => a -> String
gshow s
state
\end{code}
Thanks to the \mintinline{haskell}{Data} typeclass,
the state does not need to be an instance of \mintinline{haskell}{Show} for this to work:
\texttt{syb} offers a generic \mintinline{haskell}{gshow} function.
A more sophisticated debugger could connect to a GUI and display the state there,
even offering the user to pause the execution and edit the state live.
\fxwarning{Should I explain countDebugger? What for?}
\fxerror{Following a comment on cat theory. Add to appendix?}
\begin{comment}
Debuggers are endomorphisms in the Kleisli category of \mintinline{haskell}{IO},
and thus \mintinline{haskell}{Monoid}s:
A pair of them can be chained by executing them sequentially,
and the trivial debugger purely \mintinline{haskell}{return}s the state unchanged.
\end{comment}
We can bake a debugger into a live program:
\begin{code}
withDebugger
:: Monad m
=> LiveProgram m
-> Debugger m
-> LiveProgram m
\end{code}
\begin{comment}
\begin{code}
withDebugger :: LiveProgram m -> Debugger m -> LiveProgram m
withDebugger = (Cell m () () -> LiveProgram m
forall (m :: * -> *). Monad m => Cell m () () -> LiveProgram m
liveCell (Cell m () () -> LiveProgram m)
-> (Debugger m -> Cell m () ()) -> Debugger m -> LiveProgram m
forall b c a. (b -> c) -> (a -> b) -> a -> c
.) ((Debugger m -> Cell m () ()) -> Debugger m -> LiveProgram m)
-> (LiveProgram m -> Debugger m -> Cell m () ())
-> LiveProgram m
-> Debugger m
-> LiveProgram m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Cell m () () -> Debugger m -> Cell m () ()
forall (m :: * -> *) a b.
Monad m =>
Cell m a b -> Debugger m -> Cell m a b
withDebuggerC (Cell m () () -> Debugger m -> Cell m () ())
-> (LiveProgram m -> Cell m () ())
-> LiveProgram m
-> Debugger m
-> Cell m () ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LiveProgram m -> Cell m () ()
forall (m :: * -> *). Functor m => LiveProgram m -> Cell m () ()
toLiveCell
withDebuggerC
:: Monad m
=> Cell m a b
-> Debugger m
-> Cell m a b
withDebuggerC :: Cell m a b -> Debugger m -> Cell m a b
withDebuggerC (Cell s
state s -> a -> m (b, s)
step) (Debugger (LiveProgram dbgState dbgStep)) = Cell :: forall (m :: * -> *) a b s.
Data s =>
s -> (s -> a -> m (b, s)) -> Cell m a b
Cell { Debugging s s
Debugging s s -> a -> m (b, Debugging s s)
cellStep :: Debugging s s -> a -> m (b, Debugging s s)
cellState :: Debugging s s
cellStep :: Debugging s s -> a -> m (b, Debugging s s)
cellState :: Debugging s s
.. }
where
cellState :: Debugging s s
cellState = Debugging :: forall dbgState state.
state -> dbgState -> Debugging dbgState state
Debugging { s
s
dbgState :: s
state :: s
dbgState :: s
state :: s
.. }
cellStep :: Debugging s s -> a -> m (b, Debugging s s)
cellStep Debugging { s
s
dbgState :: s
state :: s
dbgState :: forall dbgState state. Debugging dbgState state -> dbgState
state :: forall dbgState state. Debugging dbgState state -> state
.. } a
a = do
(b
b, s
state') <- s -> a -> m (b, s)
step s
state a
a
(s, s)
states <- StateT s m s -> s -> m (s, s)
forall s (m :: * -> *) a. StateT s m a -> s -> m (a, s)
runStateT (s -> StateT s m s
dbgStep s
dbgState) s
state'
(b, Debugging s s) -> m (b, Debugging s s)
forall (m :: * -> *) a. Monad m => a -> m a
return (b
b, (s -> s -> Debugging s s) -> (s, s) -> Debugging s s
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry ((s -> s -> Debugging s s) -> s -> s -> Debugging s s
forall a b c. (a -> b -> c) -> b -> a -> c
flip s -> s -> Debugging s s
forall dbgState state.
state -> dbgState -> Debugging dbgState state
Debugging) (s, s)
states)
withDebuggerC Cell m a b
noCell Debugger m
debugger = Cell m a b -> Debugger m -> Cell m a b
forall (m :: * -> *) a b.
Monad m =>
Cell m a b -> Debugger m -> Cell m a b
withDebuggerC (Cell m a b -> Cell m a b
forall (m :: * -> *) a b. Functor m => Cell m a b -> Cell m a b
toCell Cell m a b
noCell) Debugger m
debugger
\end{code}
\end{comment}
Again, let us understand the function through its state type:
\begin{code}
data Debugging dbgState state = Debugging
{ Debugging dbgState state -> state
state :: state
, Debugging dbgState state -> dbgState
dbgState :: dbgState
} deriving (Typeable (Debugging dbgState state)
DataType
Constr
Typeable (Debugging dbgState state)
-> (forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> Debugging dbgState state
-> c (Debugging dbgState state))
-> (forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Debugging dbgState state))
-> (Debugging dbgState state -> Constr)
-> (Debugging dbgState state -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d))
-> Maybe (c (Debugging dbgState state)))
-> (forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Debugging dbgState state)))
-> ((forall b. Data b => b -> b)
-> Debugging dbgState state -> Debugging dbgState state)
-> (forall r r'.
(r -> r' -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r)
-> (forall r r'.
(r' -> r -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r)
-> (forall u.
(forall d. Data d => d -> u) -> Debugging dbgState state -> [u])
-> (forall u.
Int
-> (forall d. Data d => d -> u) -> Debugging dbgState state -> u)
-> (forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state))
-> (forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state))
-> (forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state))
-> Data (Debugging dbgState state)
Debugging dbgState state -> DataType
Debugging dbgState state -> Constr
(forall b. Data b => b -> b)
-> Debugging dbgState state -> Debugging dbgState state
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> Debugging dbgState state
-> c (Debugging dbgState state)
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Debugging dbgState state)
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Debugging dbgState state))
forall a.
Typeable a
-> (forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g) -> a -> c a)
-> (forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c a)
-> (a -> Constr)
-> (a -> DataType)
-> (forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d)) -> Maybe (c a))
-> (forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a))
-> ((forall b. Data b => b -> b) -> a -> a)
-> (forall r r'.
(r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall r r'.
(r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> a -> r)
-> (forall u. (forall d. Data d => d -> u) -> a -> [u])
-> (forall u. Int -> (forall d. Data d => d -> u) -> a -> u)
-> (forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> a -> m a)
-> (forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d) -> a -> m a)
-> Data a
forall u.
Int
-> (forall d. Data d => d -> u) -> Debugging dbgState state -> u
forall u.
(forall d. Data d => d -> u) -> Debugging dbgState state -> [u]
forall dbgState state.
(Data dbgState, Data state) =>
Typeable (Debugging dbgState state)
forall dbgState state.
(Data dbgState, Data state) =>
Debugging dbgState state -> DataType
forall dbgState state.
(Data dbgState, Data state) =>
Debugging dbgState state -> Constr
forall dbgState state.
(Data dbgState, Data state) =>
(forall b. Data b => b -> b)
-> Debugging dbgState state -> Debugging dbgState state
forall dbgState state u.
(Data dbgState, Data state) =>
Int
-> (forall d. Data d => d -> u) -> Debugging dbgState state -> u
forall dbgState state u.
(Data dbgState, Data state) =>
(forall d. Data d => d -> u) -> Debugging dbgState state -> [u]
forall dbgState state r r'.
(Data dbgState, Data state) =>
(r -> r' -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r
forall dbgState state r r'.
(Data dbgState, Data state) =>
(r' -> r -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r
forall dbgState state (m :: * -> *).
(Data dbgState, Data state, Monad m) =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
forall dbgState state (m :: * -> *).
(Data dbgState, Data state, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
forall dbgState state (c :: * -> *).
(Data dbgState, Data state) =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Debugging dbgState state)
forall dbgState state (c :: * -> *).
(Data dbgState, Data state) =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> Debugging dbgState state
-> c (Debugging dbgState state)
forall dbgState state (t :: * -> *) (c :: * -> *).
(Data dbgState, Data state, Typeable t) =>
(forall d. Data d => c (t d))
-> Maybe (c (Debugging dbgState state))
forall dbgState state (t :: * -> * -> *) (c :: * -> *).
(Data dbgState, Data state, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Debugging dbgState state))
forall r r'.
(r -> r' -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r
forall r r'.
(r' -> r -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r
forall (m :: * -> *).
Monad m =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
forall (m :: * -> *).
MonadPlus m =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
forall (c :: * -> *).
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Debugging dbgState state)
forall (c :: * -> *).
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> Debugging dbgState state
-> c (Debugging dbgState state)
forall (t :: * -> *) (c :: * -> *).
Typeable t =>
(forall d. Data d => c (t d))
-> Maybe (c (Debugging dbgState state))
forall (t :: * -> * -> *) (c :: * -> *).
Typeable t =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Debugging dbgState state))
$cDebugging :: Constr
$tDebugging :: DataType
gmapMo :: (forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
$cgmapMo :: forall dbgState state (m :: * -> *).
(Data dbgState, Data state, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
gmapMp :: (forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
$cgmapMp :: forall dbgState state (m :: * -> *).
(Data dbgState, Data state, MonadPlus m) =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
gmapM :: (forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
$cgmapM :: forall dbgState state (m :: * -> *).
(Data dbgState, Data state, Monad m) =>
(forall d. Data d => d -> m d)
-> Debugging dbgState state -> m (Debugging dbgState state)
gmapQi :: Int
-> (forall d. Data d => d -> u) -> Debugging dbgState state -> u
$cgmapQi :: forall dbgState state u.
(Data dbgState, Data state) =>
Int
-> (forall d. Data d => d -> u) -> Debugging dbgState state -> u
gmapQ :: (forall d. Data d => d -> u) -> Debugging dbgState state -> [u]
$cgmapQ :: forall dbgState state u.
(Data dbgState, Data state) =>
(forall d. Data d => d -> u) -> Debugging dbgState state -> [u]
gmapQr :: (r' -> r -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r
$cgmapQr :: forall dbgState state r r'.
(Data dbgState, Data state) =>
(r' -> r -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r
gmapQl :: (r -> r' -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r
$cgmapQl :: forall dbgState state r r'.
(Data dbgState, Data state) =>
(r -> r' -> r)
-> r
-> (forall d. Data d => d -> r')
-> Debugging dbgState state
-> r
gmapT :: (forall b. Data b => b -> b)
-> Debugging dbgState state -> Debugging dbgState state
$cgmapT :: forall dbgState state.
(Data dbgState, Data state) =>
(forall b. Data b => b -> b)
-> Debugging dbgState state -> Debugging dbgState state
dataCast2 :: (forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Debugging dbgState state))
$cdataCast2 :: forall dbgState state (t :: * -> * -> *) (c :: * -> *).
(Data dbgState, Data state, Typeable t) =>
(forall d e. (Data d, Data e) => c (t d e))
-> Maybe (c (Debugging dbgState state))
dataCast1 :: (forall d. Data d => c (t d))
-> Maybe (c (Debugging dbgState state))
$cdataCast1 :: forall dbgState state (t :: * -> *) (c :: * -> *).
(Data dbgState, Data state, Typeable t) =>
(forall d. Data d => c (t d))
-> Maybe (c (Debugging dbgState state))
dataTypeOf :: Debugging dbgState state -> DataType
$cdataTypeOf :: forall dbgState state.
(Data dbgState, Data state) =>
Debugging dbgState state -> DataType
toConstr :: Debugging dbgState state -> Constr
$ctoConstr :: forall dbgState state.
(Data dbgState, Data state) =>
Debugging dbgState state -> Constr
gunfold :: (forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Debugging dbgState state)
$cgunfold :: forall dbgState state (c :: * -> *).
(Data dbgState, Data state) =>
(forall b r. Data b => c (b -> r) -> c r)
-> (forall r. r -> c r) -> Constr -> c (Debugging dbgState state)
gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> Debugging dbgState state
-> c (Debugging dbgState state)
$cgfoldl :: forall dbgState state (c :: * -> *).
(Data dbgState, Data state) =>
(forall d b. Data d => c (d -> b) -> d -> c b)
-> (forall g. g -> c g)
-> Debugging dbgState state
-> c (Debugging dbgState state)
$cp1Data :: forall dbgState state.
(Data dbgState, Data state) =>
Typeable (Debugging dbgState state)
Data, Debugging dbgState state -> Debugging dbgState state -> Bool
(Debugging dbgState state -> Debugging dbgState state -> Bool)
-> (Debugging dbgState state -> Debugging dbgState state -> Bool)
-> Eq (Debugging dbgState state)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall dbgState state.
(Eq state, Eq dbgState) =>
Debugging dbgState state -> Debugging dbgState state -> Bool
/= :: Debugging dbgState state -> Debugging dbgState state -> Bool
$c/= :: forall dbgState state.
(Eq state, Eq dbgState) =>
Debugging dbgState state -> Debugging dbgState state -> Bool
== :: Debugging dbgState state -> Debugging dbgState state -> Bool
$c== :: forall dbgState state.
(Eq state, Eq dbgState) =>
Debugging dbgState state -> Debugging dbgState state -> Bool
Eq, Int -> Debugging dbgState state -> ShowS
[Debugging dbgState state] -> ShowS
Debugging dbgState state -> String
(Int -> Debugging dbgState state -> ShowS)
-> (Debugging dbgState state -> String)
-> ([Debugging dbgState state] -> ShowS)
-> Show (Debugging dbgState state)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall dbgState state.
(Show state, Show dbgState) =>
Int -> Debugging dbgState state -> ShowS
forall dbgState state.
(Show state, Show dbgState) =>
[Debugging dbgState state] -> ShowS
forall dbgState state.
(Show state, Show dbgState) =>
Debugging dbgState state -> String
showList :: [Debugging dbgState state] -> ShowS
$cshowList :: forall dbgState state.
(Show state, Show dbgState) =>
[Debugging dbgState state] -> ShowS
show :: Debugging dbgState state -> String
$cshow :: forall dbgState state.
(Show state, Show dbgState) =>
Debugging dbgState state -> String
showsPrec :: Int -> Debugging dbgState state -> ShowS
$cshowsPrec :: forall dbgState state.
(Show state, Show dbgState) =>
Int -> Debugging dbgState state -> ShowS
Show)
\end{code}
On every step, the debugger becomes active after the cell steps,
and is fed the current \mintinline{haskell}{state} of the main program.
Depending on \mintinline{haskell}{dbgState},
it may execute some side effects or mutate the \mintinline{haskell}{state},
or do nothing at all\footnote{%
This option is important for performance: E.g. for an audio application,
a side effect on every sample can slow down unbearably.}.
Live programs with debuggers are started just as usual.
\begin{comment}
\fxwarning{Automatise this and the next output}
Inspecting the state of the example \mintinline{haskell}{printSineWait} from Section \ref{sec:control flow context} is daunting, though:
\begin{verbatim}
Waiting...
(Composition ((,) (Composition ((,) (())
(Composition ((,) (()) (Composition ((,)
(Composition ((,) (()) (Composition ((,)
[...]
\end{verbatim}
\fxerror{I still have the tuples here!}
The arrow syntax desugaring introduces a lot of irrelevant overhead such as compositions with the trivial state type \mintinline{haskell}{()},
hiding the parts of the state we are actually interested in.
Luckily, it is a simple, albeit lengthy exercise in generic programming to prune all irrelevant parts of the state,
resulting in a tidy output%\footnote{%
%Line breaks were added to fit the columns.}
like:
\end{comment}
Let us inspect the state of the example \mintinline{haskell}{printSineWait} from Section \ref{sec:control flow context}.
It is a simple, albeit lengthy exercise in generic programming to prune all irrelevant parts of the state when printing it,
resulting in a tidy output like:
\fxwarning{Automatise this}
\begin{verbatim}
Waiting...
NotThrown: (1.0e-3)
>>> +(0.0) >>> (0.0)+ >>> (1)
NotThrown: (2.0e-3)
>>> +(0.0) >>> (0.0)+ >>> (2)
[...]
Waiting...
NotThrown: (2.0009999999998906)
>>> +(0.0) >>> (0.0)+ >>> (2001)
Exception:
>>> +(3.9478417604357436e-3) >>> (0.0)+
>>> (2002)
[...]
\end{verbatim}
\begin{comment}
Exception:
>>> +(7.895683520871487e-3) >>>
(3.947841760435744e-6)+
>>> (2003)
\end{comment}
The cell is initialised in a state where the exception hasn't been thrown yet,
and the \mintinline{haskell}{localTime} is \mintinline{haskell}{1.0e-3} seconds.
The next line corresponds to the initial state (position and velocity) of the sine generator which will be activated after the exception has been thrown,
followed by the internal counter of \mintinline{haskell}{printEverySecond}.
In the next step, local time and counter have progressed.
Two thousand steps later, the exception is finally thrown,
and the sine wave starts.
\begin{comment}
\begin{code}
newtype CountObserver = CountObserver { CountObserver -> IO Integer
observe :: IO Integer }
countDebugger :: IO (Debugger IO, CountObserver)
countDebugger :: IO (Debugger IO, CountObserver)
countDebugger = do
IORef Integer
countRef <- Integer -> IO (IORef Integer)
forall a. a -> IO (IORef a)
newIORef Integer
0
MVar Integer
observeVar <- IO (MVar Integer)
forall a. IO (MVar a)
newEmptyMVar
let debugger :: Debugger IO
debugger = (forall s. Data s => LiveProgram (StateT s IO)) -> Debugger IO
forall (m :: * -> *).
(forall s. Data s => LiveProgram (StateT s m)) -> Debugger m
Debugger ((forall s. Data s => LiveProgram (StateT s IO)) -> Debugger IO)
-> (forall s. Data s => LiveProgram (StateT s IO)) -> Debugger IO
forall a b. (a -> b) -> a -> b
$ Cell (StateT s IO) () () -> LiveProgram (StateT s IO)
forall (m :: * -> *). Monad m => Cell m () () -> LiveProgram m
liveCell (Cell (StateT s IO) () () -> LiveProgram (StateT s IO))
-> Cell (StateT s IO) () () -> LiveProgram (StateT s IO)
forall a b. (a -> b) -> a -> b
$ (() -> StateT s IO ()) -> Cell (StateT s IO) () ()
forall a (m :: * -> *) b. (a -> m b) -> Cell m a b
arrM ((() -> StateT s IO ()) -> Cell (StateT s IO) () ())
-> (() -> StateT s IO ()) -> Cell (StateT s IO) () ()
forall a b. (a -> b) -> a -> b
$ StateT s IO () -> () -> StateT s IO ()
forall a b. a -> b -> a
const (StateT s IO () -> () -> StateT s IO ())
-> StateT s IO () -> () -> StateT s IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> StateT s IO ()
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (IO () -> StateT s IO ()) -> IO () -> StateT s IO ()
forall a b. (a -> b) -> a -> b
$ do
Integer
n <- IORef Integer -> IO Integer
forall a. IORef a -> IO a
readIORef IORef Integer
countRef
MVar Integer -> Integer -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar Integer
observeVar Integer
n
IO ()
yield
IO Integer -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO Integer -> IO ()) -> IO Integer -> IO ()
forall a b. (a -> b) -> a -> b
$ MVar Integer -> IO Integer
forall a. MVar a -> IO a
takeMVar MVar Integer
observeVar
IORef Integer -> Integer -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef Integer
countRef (Integer -> IO ()) -> Integer -> IO ()
forall a b. (a -> b) -> a -> b
$ Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1
observer :: CountObserver
observer = IO Integer -> CountObserver
CountObserver (IO Integer -> CountObserver) -> IO Integer -> CountObserver
forall a b. (a -> b) -> a -> b
$ IO ()
yield IO () -> IO Integer -> IO Integer
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> MVar Integer -> IO Integer
forall a. MVar a -> IO a
readMVar MVar Integer
observeVar
(Debugger IO, CountObserver) -> IO (Debugger IO, CountObserver)
forall (m :: * -> *) a. Monad m => a -> m a
return (Debugger IO
debugger, CountObserver
observer)
await :: CountObserver -> Integer -> IO ()
await :: CountObserver -> Integer -> IO ()
await CountObserver { IO Integer
observe :: IO Integer
observe :: CountObserver -> IO Integer
.. } Integer
nMax = IO ()
go
where
go :: IO ()
go = do
Integer
n <- IO Integer
observe
if Integer
n Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
nMax then () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return () else IO ()
go
\end{code}
\end{comment}