2012-04-15 60 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...