Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/knz/hs-tracer
Tracing utilities for Haskell programmers.
https://github.com/knz/hs-tracer
Last synced: 26 days ago
JSON representation
Tracing utilities for Haskell programmers.
- Host: GitHub
- URL: https://github.com/knz/hs-tracer
- Owner: knz
- License: mit
- Created: 2014-03-22T14:38:25.000Z (over 10 years ago)
- Default Branch: master
- Last Pushed: 2014-03-22T17:05:44.000Z (over 10 years ago)
- Last Synced: 2024-09-18T16:49:18.312Z (about 2 months ago)
- Language: Haskell
- Size: 133 KB
- Stars: 3
- Watchers: 4
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.lhs
- License: LICENSE
Awesome Lists containing this project
README
==============
Debug.Tracer
==============Tracing utilities for Haskell code
==================================This library contains **Debug.Tracer**, a module that provides some
support for "print debugging" of Haskell code, and *even for pure code*: no
explicit I/O typing is required.Note: the file defining this documentation (``README.lhs``) is itself
a Haskell program, which can be run for testing the library... contents::
How to use
----------The following code defines a function ``myfact`` that computes
the factorial of an integer number::> import Debug.Tracer
>
> -- This type declaration aliases 'PureTracer PosStack',
> -- to make its name shorter for reuse.
> type Tr a = PureTracer PosStack a
>
> -- An example function using our tracer
> myfact :: Int -> Tr Int
> myfact n = do
> trace $ "entering with n = " ++ (show n)
> if n == 1 then return n
> else do
> r <- enter $ myfact (n - 1)
> trace $ "just computed r = " ++ (show r)
> return (n * r)
>
> -- The function can be used in a pure context, eg:
> myfact' :: Int -> Int
> myfact' = (runTracer "myfact") . myfactAs the example demonstrates, the **Tracer** modules allows a
programmer to write pure code in a semi-imperative style, with the
``trace`` and ``enter`` actions helping to report execution progress.For example, if we extend the example to become
a fully-fledged program::>
> main :: IO ()
> main = do
> putStrLn $ show $ myfact' 10Then this program would print a trace like the following::
1 myfact +1: entering with n = 10
4 myfact +2> +1: entering with n = 9
7 myfact +2> +2> +1: entering with n = 8
10 myfact +2> +2> +2> +1: entering with n = 7
13 myfact +2> +2> +2> +2> +1: entering with n = 6
16 myfact +2> +2> +2> +2> +2> +1: entering with n = 5
19 myfact +2> +2> +2> +2> +2> +2> +1: entering with n = 4
22 myfact +2> +2> +2> +2> +2> +2> +2> +1: entering with n = 3
25 myfact +2> +2> +2> +2> +2> +2> +2> +2> +1: entering with n = 2
28 myfact +2> +2> +2> +2> +2> +2> +2> +2> +2> +1: entering with n = 1
32 myfact +2> +2> +2> +2> +2> +2> +2> +2> +2> +3: just computed r = 1
36 myfact +2> +2> +2> +2> +2> +2> +2> +2> +3: just computed r = 2
40 myfact +2> +2> +2> +2> +2> +2> +2> +3: just computed r = 6
44 myfact +2> +2> +2> +2> +2> +2> +3: just computed r = 24
48 myfact +2> +2> +2> +2> +2> +3: just computed r = 120
52 myfact +2> +2> +2> +2> +3: just computed r = 720
56 myfact +2> +2> +2> +3: just computed r = 5040
60 myfact +2> +2> +3: just computed r = 40320
64 myfact +2> +3: just computed r = 362880
3628800Overview
--------The library can be used at two levels. At the "user" level,
the functions ``trace``, ``enter`` and ``label`` are defined
and are ready to use in do-blocks, together with
a suitable type signature as in the example above.Three monads are pre-defined at this level:
- ``PureTracer`` traces pure computations.
- ``MaybeTracer`` extends the ``Maybe`` monad with tracing.
- ``IOTracer`` extends the ``IO`` monad with tracing.In addition, **Debug.Trace** also provides a `monad
transformer`__ called **TraceT**, which can instrument any other monad
with tracing... __: http://book.realworldhaskell.org/read/monad-transformers.html
For example, to equip the ``State`` monad with tracing::
type Tr a = TraceT PosStack State a
The icing on the cake is that **TraceT** not only instruments
`Monad`__ types, but also any `Applicative`__ and `Functor`__ types... __: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Applicative.html
.. __: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Monad.html#t:Monad
.. __: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Monad.html#t:FunctorThe type "``TraceT PosXX f``" is a ``Functor`` if ``f`` is a functor,
is ``Applicative`` if ``f`` is applicative, and is a ``Monad`` if ``f`` is a monad.More examples
-------------Stacking vs. non-stacking with ``enter``
````````````````````````````````````````If a (pure) function "looks" like a flat loop, chances are its trace
will be flat, too::> let
> myfact2 :: Int -> Int -> Tr Int
> myfact2 r n = do
> trace $ "processing n = " ++ (show n) ++ ", r = " ++ (show r)
> if n == 1 then return r
> else myfact2 (n * r) (n - 1)
> putStrLn $ show $ runTracer "myFact2" $ myfact2 1 10This program, which avoids using ``enter``, would print::
1 myFact2 +1: processing n = 10, r = 1
2 myFact2 +2: processing n = 9, r = 10
3 myFact2 +3: processing n = 8, r = 90
4 myFact2 +4: processing n = 7, r = 720
5 myFact2 +5: processing n = 6, r = 5040
6 myFact2 +6: processing n = 5, r = 30240
7 myFact2 +7: processing n = 4, r = 151200
8 myFact2 +8: processing n = 3, r = 604800
9 myFact2 +9: processing n = 2, r = 1814400
10 myFact2 +10: processing n = 1, r = 3628800
3628800The "stacking" in the output follows the uses of the action
``enter``. To avoid stacking, simply leave ``enter`` away.Relative counts with ``label``
``````````````````````````````In a complex computation, the action ``label`` can mark basic blocks,
as follows::> let
> complex :: Int -> Tr Int
> complex n = do
> label "start"
> x <- return $ 1 - n
> y <- return $ 2 * n
> t <- return $ x * y
> trace $ "here t = " ++ (show t)
> u <- return $ y - t
>
> label "middle"
> v <- return $ t * x
> trace $ "v = " ++ (show v)
>
> m <- return $ n * n
> o <- return $ m + m + u + v
> label "end"
> trace $ "returning o = " ++ (show o)
> return o
> putStrLn $ show $ runTracer "complex" $ complex 10This could print the following trace::
12 complex start+11: here t = -180
21 complex middle+5: v = 1620
30 complex end+2: returning o = 2020
2020Note how the count on the left is global (shared by the entire tracing
compound), whereas the count on the right is local, relative to the
point a label was last positioned.Ordering with other side-effects
``````````````````````````````````Traces play well with other side effects. For example,
I/O actions are properly ordered::> let
> someio :: Int -> TrIO ()
> someio n = do
> d <- return $ n + n
> trace "before io"
> lift $ putStrLn $ "d = " ++ (show d)
> trace "after io"
> return ()
>
> runTracerT "someio" (someio 10)This program would print as expected::
4 someio +4: before io
d = 20
8 someio +8: after ioWith the message "``d = 20``" properly interleaved with trace
messages.Note: the examples above also use the following type declaration::
> type TrIO a = IOTracer PosStack a