2016-11-22 12 views
5

idとして最適化すると、GHCはassertを書き換えます。あるいは、その動作はコンパイラフラグで変更することができます。しかし、同じことがtraceでは起こらないことに気付きました。 traceのバージョンは、フラグが設定されていないか、設定されていない場合はidとなりますか?「トレース」を「アサート」のように最適化しますか?

より一般的に言えば、(コンパイルに使用されるフラグではなく)呼び出し元モジュールをコンパイルするために使用されるコンパイラフラグに基づいて関数の動作を変更する方法があります。まるでassertのように。あるいは、GHCの魔法はassertでしか起こりませんか?

+4

私はこれらのような質問に答えることについて常にフェンスにいます。 "私は道を知りません"というのは本当の答えではありませんが、誰もそれを言うつもりがなければ、まったく反応がありません。 –

+0

GHCはいくつかの別々のコンパイルを行います。定義モジュールがアンフォールディングを公開していない場合、呼び出しモジュールはオブジェクトコードでスタックされます。 – dfeuer

+3

私のコンピュータでは今はありませんが、assert内でトレースを呼び出すことはどうですか? –

答えて

6

いいえ、少なくともassertに基づいていません。 assertの魔法は反対方向に働き、アイデンティティ関数をアサーションに置き換えます。

ここ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を除いて、ベースパッケージからincluding every moduleによってghcへの引数のDebug.Traceモジュールを非表示にします。 Debug.TraceをパッケージのNoTraceに交換してください。

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

これはtrace Sを削除するrewrite rulesを持っていたものとプレリュードを交換するのプレリュードを変更するコンパイラフラグを使用してのクレイジーなアイデアから来たが、それらの書き換えルールは、モジュールをインポートしたものを汚染チェックでしょう下流の輸入者が依然として痕跡を使用したがっているにもかかわらず、それらとともに編集された。前奏曲を置き換える方法を調べると、ghcは代わりにどのモジュールも置き換えることができることがわかりました。

5

OK、私のコンピュータに戻って、最後に私はこれを実証したかったと思いました。ここに行く:

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一度サンクが評価されると、それは2回目に評価されません(メッセージが最初にでのみ発生する理由です-block)。

関連する問題