
Chris Seaton
I use printf-style debugging a lot, so I am always adding and removing applications of trace. There is the Debug.Trace.traceIO function that makes this easy to do in the IO monad (it just applies hPutStrLn stderr), but is that specialisation to IO unnecessary?
I find myself always using this utility function:
traceM :: (Monad m) => String -> m () traceM message = trace message $ return ()
Which can be used to implement traceIO.
traceIO :: String -> IO () traceIO = traceM
btw, that wouldn't have the same semantics as the existing `Debug.Trace.traceIO` which is more or less something similiar to a `hPutStrLn stderr` whose side-effect gets triggered at monad-execution time, whereas the side-effect of `traceM` occurs at monad-construction time; consider the following program: --8<---------------cut here---------------start------------->8--- import Control.Monad import Debug.Trace traceM :: (Monad m) => String -> m () traceM message = trace message $ return () traceIO' :: String -> IO () traceIO' = traceM main = replicateM_ 5 $ do trace1 trace2 where trace1 = traceIO' "trace1" trace2 = traceIO "trace2" --8<---------------cut here---------------end--------------->8--- when run via runghc (or compiled with -O0) for GHC 7.6, this emits --8<---------------cut here---------------start------------->8--- trace1 trace2 trace2 trace2 trace2 trace2 --8<---------------cut here---------------end--------------->8--- only when using -O1 or -O2 the output results in --8<---------------cut here---------------start------------->8--- trace1 trace2 trace1 trace2 trace1 trace2 trace1 trace2 trace1 trace2 --8<---------------cut here---------------end--------------->8--- (I'm guessing this due to `trace1` being inlined for -O1/-O2 -- but I haven't checked) cheers, hvr