2016-11-22 26 views
5

GHC重寫assert時優化只是id。或者,它的行爲可以通過編譯器標誌來改變。不過,我注意到trace也沒有發生同樣的情況。如果標誌未被設置或被設置,是否有trace的版本,最終結果爲id像「assert」一樣優化「跟蹤」?

更一般地說,是否有方法根據用於編譯調用模塊的編譯器標誌(而不是用於編譯自身的標誌)來改變函數的行爲。就像assert一樣。或者這是GHC的魔法,只能發生在assert

+4

我一直在回答這樣的問題。 「我不知道一種方式」並不是一個真正的答案,但如果沒有人願意說出來,那麼你根本就沒有迴應...... –

+0

GHC做了一些單獨的編譯。如果定義模塊沒有展示展開,則調用模塊將被粘貼目標代碼。 – dfeuer

+3

現在不在我的計算機上,但是如何在呼叫中追蹤呼叫並讓整個斷言得到優化呢? –

回答

6

不,至少不是基於assertassert的神奇作用於另一個方向,並用斷言取代身份函數。

這裏是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 @[email protected] or the @[email protected] 
-- 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 
9

警告:我沒有嘗試這樣做......

你可以用編譯器標誌完全取代Debug.Trace模塊。請與功能瑣碎實現另一個模塊中Debug.Trace

module NoTrace (trace) where: 

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

... 

把這個模塊在一個名爲no-trace另一個包。

Debug.Trace模塊隱藏在ghc的參數中including every module從基本包中除外Debug.Trace。將Debug.Trace替換爲no-trace包中的NoTrace

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

在此之前使用的是改變了序幕,以取代一個有rewrite rules刪除trace S中的前奏編譯器標誌的瘋狂的想法,但這些重寫規則將玷污任何進口模塊與他們一起編譯,即使下游進口商仍想使用痕跡。在查找如何替換前奏時,我發現ghc可以替代任何模塊。

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"() 

當沒有優化編譯,輸出爲:

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

隨着優化:

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

所以我覺得這個地址的要​​求,與各地標準告誡trace一旦thunk被評估過,它將不會被第二次評估(這就是爲什麼這些消息只發生在第一次通過do -block)。