通过Haskell中的I / O测试函数

时间:2015-07-27 16:20:33

标签: debugging haskell testing

我正在玩代码大战来提高我的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的标准做法?他们是否以其他方式绕过它?

1 个答案:

答案 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