我正在玩代码大战来提高我的Haskell技能,并遇到一个我在命令式语言中无法解决的问题。
让我们说我在javascript中编写一个函数foo(),它接受一个int,加两个,加上一个,减去一个,然后返回该数字的平方根。
var foo = function(n) {
n += 2;
n = n * n;
n -= 1;
n = Math.sqrt(n);
}
我想在各个点检查函数中正在处理的数据的状态,以帮助我排除故障/修改/调试代码,所以每当我想看看我在哪里时,我都会插入console.log()语句。我在。例如,我实际上是在函数的正中途正确地计算n + 2的总和吗?我们来看看......
var foo = function(n) {
n += 2;
n = n * n;
console.log("n = " + n);
n -= 1;
n = Math.sqrt(n);
}
虽然这个例子应该足够简单,以便Haskeller能够在一行中写入,但如果你有一个复杂的函数并想要在不同的点检查状态,那么Haskellers如何做呢?是否有使用IO()monad的标准做法?他们是否以其他方式绕过它?
答案 0 :(得分:6)
GHCi有一个花哨的debugger,它允许您逐步执行代码并逐行评估,检查它的状态和中间结果。
但是,当然,使用printf
中的trace
函数,您还需要进行Debug.Trace
式调试。使用它对于小脚本imho没有错,但通常不鼓励。
trace
的类型为String -> a -> a
,因此您传递一个打印的字符串(通过unsafePerformIO
)和任何简单返回的参数。
在您的示例中,我们可以按如下方式使用它。这是你的功能翻译成Haskell:
foo x = sqrt $ (x+2)**2 - 1
现在我们只需添加trace
和我们想要查看的字符串,例如"Debug Me: " ++ (show ((x+2)**2))
。首先导入Debug.Trace
,但是:
import Debug.Trace
foo x = sqrt $ (trace ("Debug Me: " ++ (show ((x+2)**2))) ((x+2)**2)) - 1
有点难看?根据David Young在下面的评论,我们最好使用traceShowId :: Show a => a -> a
,如果我们想要输出的内容与中间结果相同(当然转换为String
):
import Debug.Trace
foo x = sqrt $ (traceShowId ((x+2)**2)) - 1
有关调试选项的摘要,请参阅here。