2012-04-15 6 views
2

Ich habe ein Projekt für Uni, um einen Compiler (in Haskell) für eine einfache erfundene imperative Sprache zu schreiben. Eine der Anforderungen besteht darin, Debug-Anweisungen beim Eingeben eines Funktionsaufrufs zu drucken, eine Funktion zu verlassen und Variablen zuzuweisen.Haskell - Drucken einer Ablaufverfolgung nach der Ausführung

Nachrichten Drucken, wenn Funktionen Eingabe einfach ist, benutze ich nur Debug.trace, zB:

functionValue = trace "Entering function" (evaluateFunction functionArguments) 

Das gleiche Verfahren gilt, wenn auf Variablen zugewiesen wird. Was ich nicht herausfinden kann, ist, wie man druckt, wenn man von einem Funktionsaufruf zurückkehrt und den Ausgang korrekt mit den anderen Ausgaben synchronisiert hat. Jeder Versuch, den ich bisher gemacht habe, hat dazu geführt, dass "Leaving function" unmittelbar nach "Entering function" gedruckt wurde - ich brauche die internen Debug-Anweisungen der Funktion (Zuweisungen und verschachtelte Funktionsaufrufe), bevor "Leaving function" gedruckt wird.

Meine Imperativgewohnheiten sagen mir, dass ich eine Möglichkeit brauche, die Ausführung von (evaluateFunction functionArguments) vor der leave-function-Ausgabe zu erzwingen, aber das scheint in Haskell unmöglich und falsch zu sein.

Beispiel Ausgabe erhalte ich jetzt:

Entering main function... 
Leaving main function... 
Entering fn1 function... 
Leaving fn1 function... 
Assigning value1 to A. 
Assigning value2 to C. 
Entering fn2 function... 
Leaving fn2 function... 
Assigning value3 to B. 
Assigning value4 to C. 

gleiche Programmausgabe so, wie ich es muss aussehen:

Entering main function... 
Entering fn1 function... 
Assigning value1 to A. 
Leaving fn1 function... 
Assigning value2 to C. 
Entering fn2 function... 
Assigning value3 to B. 
Assigning value4 to C. 
Leaving fn2 function... 
Leaving main function... 

Also, was ist Haskell Idiom für 'laufen myFunctionWithTraces dann drucken myString'?

+4

Da Sie sicherstellen müssen, dass Nachrichten in einer bestimmten Reihenfolge gedruckt werden, sollten Sie Debug.Trace nicht verwenden. Biss stattdessen die Kugel, renne in IO und benutze 'putStrLn' oder ähnliches. – dave4420

+0

Kompilieren Sie nach Haskell? –

Antwort

5

Wenn Sie sofort Spuren drucken möchten, können Sie die Funktion auf IO-Monade anheben und zwischen zwei putStr s, z.

trace :: String -> IO() -> IO() 
trace name f = do 
    putStrLn $ "Entering " ++ name 
    f 
    putStrLn $ "Leaving " ++ name 

Und dann:

main = trace "main" $ do 
    fn1 
    fn2 

fn1 = trace "fn1" $ do 
    return() 

fn2 = trace "fn2" $ do 
    return() 

Dies kann auch rein getan werden, mit dem Writer Monade (das heißt nicht gedruckt, sondern nur akkumulieren Debugging-Ausgabe, wie Sie gehen). trace würde dann mehr wie folgt aussehen:

trace :: String -> Writer String() -> Writer String() 
trace name f = do 
    tell $ "Entering " ++ name ++ "\n" 
    f 
    tell $ "Leaving " ++ name ++ "\n" 

und mit zusätzlichen Schritt die Debug-Ausgabe mit runWriter oder execWriter auszupacken.

Edit: verallgemeinern trace zu IO a nicht allzu schwer:

trace :: String -> IO a -> IO a 
trace name f = do 
    putStrLn $ "Entering " ++ name 
    ret <- f 
    putStrLn $ "Leaving " ++ name 
    return ret 

main = trace "main" $ do 
    a <- fn1 
    b <- fn2 
    print $ a + b 

fn1 = trace "fn1" $ do 
    return 42 

fn2 = trace "fn2" $ do 
    return 69 
+0

@drodgers: Siehe meine Bearbeitung. –

+0

Ich habe es! Vielen Dank. – drodgers

1

[Der Code wurde nicht lesbar in einem Kommentar so gab ich eine andere Antwort als Kommentar zu Cat Plus Plus]

Ich habe schließlich habe ich die IO-Monade durch meinen ganzen Code gefädelt, aber diese Lösung funktioniert nicht ganz - ich muss Rückgabewerte (dh IO (Wert)) aus meinen Funktionen herausholen.

do 
    putStrLn $ "Entering " ++ name 
    f 
    putStrLn $ "Leaving " ++ name 

Der obige Schnipsel kehrt IO() (die leere IO monadisch).So modifizierte ich es sein:

do 
    putStrLn $ "Entering " ++ name 
    returnVal <- f 
    putStrLn $ "Leaving " ++ name 
    return (returnVal) 

Aber das ist jetzt Druck:

innen Funktion Aktionen ... ... ... Funktion Eingabe Verlassen Funktion

Edit: Die falsche Ausgabe wurde war meine Schuld: Ich versehentlich result <- fvorputStrLn "Entering...

Verwandte Themen