2012-04-15 62 views
2

我有一個項目讓Uni編寫一個編譯器(在Haskell中),用於編寫一個簡單的命令式語言。其中一個要求是在輸入函數調用時打印調試語句,留下一個函數並分配變量。Haskell - 執行後打印跟蹤

打印郵件時輸入的功能很簡單,我只是用Debug.trace,如:

functionValue = trace "Entering function" (evaluateFunction functionArguments) 

同樣的過程分配給變量時適用。我無法弄清楚的是如何從函數調用返回時打印,並使輸出與其他輸出的時間正確。到目前爲止,我所做的每一次嘗試都導致在「輸入函數」後立即打印「離開函數」 - 我需要在打印「離開函數」之前打印函數的內部調試語句(分配和嵌套函數調用)。

我的迫切習慣告訴我,我需要一種方法來在離開函數輸出之前強制執行(evaluateFunction functionArguments),但這在Haskell中似乎是不可能和錯誤的。

示例輸出我現在得到:

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. 

同一個程序的輸出我需要它的樣子:

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... 

那麼,什麼是Haskell的成語爲 '運行myFunctionWithTraces然後打印的myString'?

+4

由於您需要保證消息按特定順序打印,因此不應使用Debug.Trace。相反,咬一口,運行IO,並使用'putStrLn'或類似的東西。 – dave4420 2012-04-15 08:33:23

+0

你在編譯Haskell嗎? – 2012-04-15 08:42:47

回答

5

如果要立即打印曲線,可以將函數提升到IO monad,並將其放在兩個putStr之間,例如,

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

然後:

main = trace "main" $ do 
    fn1 
    fn2 

fn1 = trace "fn1" $ do 
    return() 

fn2 = trace "fn2" $ do 
    return() 

這也可以做到純粹,與Writer單子(即不打印,只是積累調試輸出,當您去)。然後trace看起來更像是這樣的:

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

,並與runWriterexecWriter展開調試輸出的額外步驟。

編輯:要概括traceIO a並不太難:

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:查看我的編輯。 – 2012-04-22 18:20:22

+0

我明白了!謝謝。 – drodgers 2012-04-22 18:45:43

1

[代碼是不可讀的評論,所以我貼的另一個答案,貓加上加評論]

我已經最後通過我所有的代碼對IO monad進行了線程化處理,但是這個解決方案並不能正常工作 - 我需要從我的函數中獲取返回值(即IO(value))。

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

上面的代碼片段將返回IO()(空IO單元)。所以我修改它是:

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

但這種情況正在打印:

內部功能的行動... ... ... 進入 功能 離開功能

編輯:不正確的輸出得到是我的錯:我不小心把result <- f之前putStrLn "Entering...