To make the trace optimized, how to assert?

GHC overwrites assert during optimization only as id . Or, conversely, this behavior can be changed using the compiler flag. However, I noticed that the same thing does not happen with trace . Is there a version of trace that ends as id if the flag is not set or set?

More generally, is there a way to change the behavior of a function based on the compiler flags used to compile the calling module (rather than the flags used to compile). Very similar to assert . Or is it GHC magic that can only happen with assert ?

+5
source share
3 answers

Warning: I have not tried this ...

You can completely replace the Debug.Trace module with compiler flags. Make another module with trivial function implementations in Debug.Trace :

 module NoTrace (trace) where: trace :: String -> a -> a {-# INLINE trace #-} trace _message = id ... 

Put this module in another package called no-trace .

Hide the Debug.Trace module in ghc arguments including every module from the base package, except Debug.Trace . Replace Debug.Trace with NoTrace from the no-trace package.

 ghc -package="base (Control, Control.Applicative, ..., Data.Word, Foreign, ...)" \ -package="no-trace (NoTrace as Debug.Trace)" \ ... 

This was due to the crazy idea of ​​using a compiler flag that modifies the prelude to replace the prelude for those who rewrite the rules in order to remove trace s, but these rewrite rules will damage everything that the module compiled with them imports, even if the downstream importer still wants to use traces. When searching for how to replace the prelude, I found that ghc can replace any module.

+9
source

No, at least not based on assert . The magic for assert works in a different direction and replaces the identification function with a statement.

Here's an assert from base 4.9 :

 -- Assertion function. This simply ignores its boolean argument. -- The compiler may rewrite it to @('assertError' line)@. -- | If the first argument evaluates to 'True', then the result is the -- second argument. Otherwise an 'AssertionFailed' exception is raised, -- containing a 'String' with the source file and line number of the -- call to 'assert'. -- -- Assertions can normally be turned on or off with a compiler flag -- (for GHC, assertions are normally on unless optimisation is turned on -- with @ -O@ or the @ -fignore-asserts@ -- option is given). When assertions are turned off, the first -- argument to 'assert' is ignored, and the second argument is -- returned as the result. -- SLPJ: in 5.04 etc 'assert' is in GHC.Prim, -- but from Template Haskell onwards it simply -- defined here in Base.lhs assert :: Bool -> a -> a assert _pred r = r 
+6
source

OK, back to your computer and finally remembered that I wanted to demonstrate this. Here:

 import Control.Exception import Debug.Trace import Control.Monad traceDebug :: String -> a -> a traceDebug msg = assert (trace msg True) main :: IO () main = replicateM_ 2 $ do print $ traceDebug "here1" () print $ traceDebug "here2" () print $ traceDebug "here3" () 

When compiling without optimization, the output is:

 here1 () here2 () here3 () () () () 

With optimization:

 () () () () () () 

So, I think this addresses the request with the standard warning around trace that after thunk has been evaluated, it will not be evaluated a second time (therefore, messages only happen the first time through a do block).

+5
source

Source: https://habr.com/ru/post/1260114/


All Articles