\begin{code} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE FlexibleInstances #-} \end{code} %************************************************************************ %* * \subsection{Exports} %* * %************************************************************************ \begin{code} module Debug.Hood.Observe ( -- * The main Hood API observe -- (Observable a) => String -> a -> a , Observer(..) -- contains a 'forall' typed observe (if supported). , Observing -- a -> a , Observable(..) -- Class , runO -- IO a -> IO () , printO -- a -> IO () , putStrO -- String -> IO () -- * For advanced users, that want to render their own datatypes. , (<<) -- (Observable a) => ObserverM (a -> b) -> a -> ObserverM b , thunk -- (Observable a) => a -> ObserverM a , send , observeBase , observeOpaque -- * For users that want to write there own render drivers. , debugO -- IO a -> IO [CDS] ) where \end{code} %************************************************************************ %* * \subsection{Imports and infixing} %* * %************************************************************************ \begin{code} import System.IO import Data.Maybe import Control.Monad import Data.List --import System -- The only non standard one we assume --import IOExts import Data.IORef import System.IO.Unsafe \end{code} \begin{code} import Control.Concurrent \end{code} \begin{code} import Control.Exception ( Exception, throw ) import qualified Control.Exception as Exception {- ( catch , Exception(..) , throw ) as Exception -} \end{code} \begin{code} infixl 9 << \end{code} %************************************************************************ %* * \subsection{External start functions} %* * %************************************************************************ Run the observe ridden code. \begin{code} printO :: a -> IO () printO expr = return () putStrO :: String -> IO () putStrO expr = return () runO :: IO a -> IO () runO _ = return () debugO _ = return [] \end{code} %************************************************************************ %* * \subsection{Simulations} %* * %************************************************************************ Here we provide stubs for the functionally that is not supported by some compilers, and provide some combinators of various flavors. \begin{code} \end{code} %************************************************************************ %* * \subsection{Instances} %* * %************************************************************************ The Haskell Base types \begin{code} instance Observable a observeBase :: a -> Parent -> a observeBase x _ = x observeOpaque :: String -> a -> Parent -> a observeOpaque _ val _ = val \end{code} %************************************************************************ %* * \subsection{Classes and Data Definitions} %* * %************************************************************************ \begin{code} class Observable a where {- - This reveals the name of a specific constructor. - and gets ready to explain the sub-components. - - We put the context second so we can do eta-reduction - with some of our definitions. -} observer :: a -> Parent -> a {- - This used used to group several observer instances together. -} observers :: String -> (Observer -> a) -> a type Observing a = a -> a \end{code} \begin{code} newtype Observer = O (forall a . (Observable a) => String -> a -> a) \end{code} %************************************************************************ %* * \subsection{The ObserveM Monad} %* * %************************************************************************ The Observer monad, a simple state monad, for placing numbers on sub-observations. \begin{code} newtype ObserverM a = ObserverM { runMO :: Int -> Int -> (a,Int) } \end{code} %************************************************************************ %* * \subsection{observe and friends} %* * %************************************************************************ Our principle function and class \begin{code} -- | 'observe' observes data structures in flight. -- -- An example of use is -- @ -- map (+1) . observe \"intermeduate\" . map (+2) -- @ -- -- In this example, we observe the value that flows from the producer -- @map (+2)@ to the consumer @map (+1)@. -- -- 'observe' can also observe functions as well a structural values. -- {-# NOINLINE observe #-} observe :: (Observable a) => String -> a -> a observe name a = a {- This gets called before observer, allowing us to mark - we are entering a, before we do case analysis on - our object. -} {-# NOINLINE observer_ #-} observer_ :: (Observable a) => a -> Parent -> a observer_ a context = a \end{code} \begin{code} data Parent = Parent { observeParent :: !Int -- my parent , observePort :: !Int -- my branch number } deriving Show root = Parent 0 0 instance Monad ObserverM where return a = ObserverM (\ c i -> (a,i)) fn >>= k = ObserverM (\ c i -> case runMO fn c i of (r,i2) -> runMO (k r) c i2 ) thunk :: (Observable a) => a -> ObserverM a thunk a = ObserverM $ \ parent port -> ( observer_ a (Parent { observeParent = parent , observePort = port }) , port+1 ) (<<) :: (Observable a) => ObserverM (a -> b) -> a -> ObserverM b fn << a = do { fn' <- fn ; a' <- thunk a ; return (fn' a') } send = undefined \end{code}