GHC rewrites assert
s when optimising as just id
. Or alternatively, it's behaviour can be changed with a compiler flag. However, I noticed the same doesn't happen with trace
. Is there a version of trace
which just ends up as id
if a flag isn't or is set?
More generally speaking, is there a way to alter the behaviour of a function based on the compiler flags used to compile the calling module (not the flags used to compile itself). Much like assert
does. Or is this GHC magic that can only happen with assert
?
Asserts are used primarily to validate that the code you or others on your team write is behaving correctly. Asserts should generally not be used when you are trying to validate code from other developers. You should check return values, validate them, and if they are invalid, raise errors or error codes.
An assert statement consists of the assert keyword, the expression or condition to test, and an optional message. The condition is supposed to always be true. If the assertion condition is true, then nothing happens, and your program continues its normal execution.
Assert(Boolean, Debug+AssertInterpolatedStringHandler) Checks for a condition; if the condition is false , outputs a specified message and displays a message box that shows the call stack.
Assert(Boolean, String) evaluates the condition. If the result is false , it sends the specified diagnostic message to the Listeners collection. You can customize this behavior by adding a TraceListener to, or removing one from, the Listeners collection.
No, at least not based on assert
. The magic for assert
works the other direction and replaces the identity function with an assertion.
Here's 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's simply -- defined here in Base.lhs assert :: Bool -> a -> a assert _pred r = r
OK, back at my computer and finally remembered I wanted to demonstrate this. Here goes:
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 compiled without optimizations, the output is:
here1
()
here2
()
here3
()
()
()
()
With optimizations:
()
()
()
()
()
()
So I think this addresses the request, with the standard caveat around trace
that once the thunk has been evaluated, it won't be evaluated a second time (which is why the messages only happen the first time through the do
-block).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With