dro*_*ers 2 io monads trace haskell side-effects
我有一个让Uni编写一个编译器(在Haskell中)的项目,用于编写简单的命令式语言.其中一个要求是在进入函数调用时打印调试语句,保留函数并分配变量.
输入函数时打印消息很简单,我只使用Debug.trace,例如:
functionValue = trace "Entering function" (evaluateFunction functionArguments)
Run Code Online (Sandbox Code Playgroud)
分配给变量时也适用相同的过程.我无法弄清楚当从函数调用返回时如何打印并且输出与其他输出正确地计时.到目前为止我所做的每一次尝试都导致在"输入功能"之后立即打印"离开功能" - 我需要在打印"离开功能"之前打印功能的内部调试语句(分配和嵌套函数调用).
我的命令习惯告诉我,我需要一种方法来在执行leave-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.
Run Code Online (Sandbox Code Playgroud)
相同程序的输出方式我需要它看起来:
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...
Run Code Online (Sandbox Code Playgroud)
那么,什么是'运行myFunctionWithTraces然后打印myString'的Haskell成语?
如果要立即打印迹线,可以将功能提升到IO monad,并将其置于两个putStrs 之间,例如
trace :: String -> IO () -> IO ()
trace name f = do
putStrLn $ "Entering " ++ name
f
putStrLn $ "Leaving " ++ name
Run Code Online (Sandbox Code Playgroud)
然后:
main = trace "main" $ do
fn1
fn2
fn1 = trace "fn1" $ do
return ()
fn2 = trace "fn2" $ do
return ()
Run Code Online (Sandbox Code Playgroud)
这也可以完全用Writermonad完成(即不打印,但只是累积调试输出).trace那么看起来会更像这样:
trace :: String -> Writer String () -> Writer String ()
trace name f = do
tell $ "Entering " ++ name ++ "\n"
f
tell $ "Leaving " ++ name ++ "\n"
Run Code Online (Sandbox Code Playgroud)
并使用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
Run Code Online (Sandbox Code Playgroud)