通过Haskell中的I/O测试功能

Mar*_*van 3 testing debugging haskell

我正在玩代码大战来提高我的Haskell技能,并遇到一个我在命令式语言中没有的问题.

假设我在javascript中编写一个函数foo(),它接受一个int,加两个,正方形,减去一个,然后返回该数字的平方根.

var foo = function(n) {
  n += 2;
  n = n * n;
  n -= 1;
  n = Math.sqrt(n);
}
Run Code Online (Sandbox Code Playgroud)

我想在各个点检查函数中正在处理的数据的状态,以帮助我排除故障/修改/调试代码,所以每当我想看看我在哪里时,我都会插入console.log()语句.例如,我实际上是在函数的正中途正确地计算n + 2的总和吗?让我们来看看...

var foo = function(n) {
  n += 2;
  n = n * n;
  console.log("n = " + n);
  n -= 1;
  n = Math.sqrt(n);
}
Run Code Online (Sandbox Code Playgroud)

虽然这个例子应该足够简单,以便Haskeller能够在一行中写入,但如果你有一个复杂的函数并想要在不同的点检查状态,那么Haskellers如何做呢?是否有使用IO()monad的标准做法?他们是否以其他方式绕过它?

lod*_*rik 6

GHCi有一个花哨的调试器,它允许您逐步执行代码并逐行评估它,检查它的状态和中间结果.

但是,当然printf,使用trace函数from 还有你要求的样式调试Debug.Trace.将它用于小脚本imho没有错,但通常不鼓励.

trace有类型String -> a -> a,所以你传递一个被打印的字符串(via unsafePerformIO)和任何简单返回的参数.


在您的示例中,我们可以按如下方式使用它.这是你的功能翻译成Haskell:

foo x = sqrt $ (x+2)**2 - 1
Run Code Online (Sandbox Code Playgroud)

现在我们可以添加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
Run Code Online (Sandbox Code Playgroud)

有点难看?根据David Young在下面的评论traceShowId :: Show a => a -> a,如果我们想要输出的内容与中间结果相同(String当然转换为),我们会更好地使用:

import Debug.Trace
foo x = sqrt $ (traceShowId ((x+2)**2)) - 1 
Run Code Online (Sandbox Code Playgroud)

有关调试选项的摘要,请参见此处.

  • `trace(show y)y`可以简化为`traceShowId y` (2认同)