像"断言"一样使"跟踪"优化?

Cli*_*ton 5 debugging haskell ghc

GHC assert在优化时重写s id.或者,可以使用编译器标志更改其行为.但是,我注意到同样的情况不会发生trace.是否有一个版本trace刚刚结束,id好像一个标志没有或被设置?

更一般地说,有没有办法根据用于编译调用模块的编译器标志(而不是用于编译自身的标志)来改变函数的行为.很像assert.或者这种GHC魔法是否只会发生assert

Cir*_*dec 9

警告:我没试过这个......

您可以Debug.Trace使用编译器标志完全替换模块.使用以下函数的简单实现创建另一个模块Debug.Trace:

module NoTrace (trace) where:

trace :: String -> a -> a
{-# INLINE trace #-}
trace _message = id

...
Run Code Online (Sandbox Code Playgroud)

将此模块放在另一个名为的包中no-trace.

Debug.Trace通过包含基础包中的每个模块来隐藏ghc参数中的模块Debug.Trace.替换Debug.TraceNoTraceno-trace包.

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

这来自于使用编译器标志的疯狂想法,该标志改变了前奏,用一个具有重写规则来删除traces 的前缀替换前奏,但是这些重写规则会污染导入用它们编译的模块的任何内容,即使下游导入器仍然存在想用痕迹.在查找如何替换前奏时,我发现ghc可以替换任何模块.


Cir*_*dec 6

不,至少不是基于assert.神奇的assert工作方向是另一个方向,并用断言取代身份功能.

这是assert基地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
Run Code Online (Sandbox Code Playgroud)


Mic*_*man 5

好的,回到我的电脑,最后还记得我想证明这一点.开始:

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" ()
Run Code Online (Sandbox Code Playgroud)

在没有优化的情况下编译时,输出为:

here1
()
here2
()
here3
()
()
()
()
Run Code Online (Sandbox Code Playgroud)

通过优化:

()
()
()
()
()
()
Run Code Online (Sandbox Code Playgroud)

所以我认为这解决了请求,标准警告trace一旦thunk被评估,它将不会被第二次评估(这就是为什么消息只在第一次通过do-block时发生).