我有一个让Uni编写一个编译器(在Haskell中)的项目,用于编写简单的命令式语言。其中一个要求是在进入函数调用时打印调试语句,保留函数并分配变量。
输入功能时打印信息很简单,我只使用Debug.trace,例如:
functionValue = trace "Entering function" (evaluateFunction functionArguments)
分配给变量时应用相同的过程。我无法弄清楚当从函数调用返回时如何打印并且输出与其他输出正确地计时。到目前为止,我所做的每一次尝试都导致了“离开”功能"在"输入功能"之后立即打印 - 我需要在" Leaving function"之前打印函数的内部调试语句(赋值和嵌套函数调用)。打印出来。
我的命令习惯告诉我在离开函数输出之前需要一种强制执行(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'?
答案 0 :(得分: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
monad完成(即不打印,但只是累积调试输出)。 trace
看起来更像是这样:
trace :: String -> Writer String () -> Writer String ()
trace name f = do
tell $ "Entering " ++ name ++ "\n"
f
tell $ "Leaving " ++ name ++ "\n"
以及使用runWriter
或execWriter
展开调试输出的附加步骤。
修改:将trace
推广到IO 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
答案 1 :(得分:1)
[代码在评论中不可读,所以我发布了另一个答案作为对Cat Plus Plus的评论]
我终于通过我的所有代码对IO monad进行了线程化,但是这个解决方案并不是很有效 - 我需要从函数中获取返回值(即IO(值))。
do
putStrLn $ "Entering " ++ name
f
putStrLn $ "Leaving " ++ name
上面的代码片段将返回IO()(空IO monad)。所以我把它修改为:
do
putStrLn $ "Entering " ++ name
returnVal <- f
putStrLn $ "Leaving " ++ name
return (returnVal)
<击> 但现在打印:
内部功能动作......
...
...
输入功能
离开功能
击>
编辑:输出错误是我的错:我不小心将result <- f
放在 putStrLn "Entering...