我在使用Haskell编写小型工具方面有一些经验,我发现使用起来非常直观,尤其是对于编写过滤器(使用interact
)来处理其标准输入并将其通过管道传输到标准输出。
最近,我尝试在比通常大10倍的文件上使用这样的过滤器,但出现Stack space overflow
错误。
在阅读了一些内容之后(例如,在这里和这里),我确定了两个节省堆栈空间的准则(有经验的Haskellers,如果我写的东西不正确,请纠正我):
- 避免使用非尾递归的递归函数调用(这对所有支持尾调用优化的功能语言均有效)。
- 引入
seq
强制对子表达式进行早期评估,以使表达式在被缩减之前不会变得太大(这是Haskell所特有的,或者至少是使用惰性评估的语言所特有的)。
seq
在我的代码中引入了五到六个调用之后,我的工具再次运行平稳(也适用于较大的数据)。但是,我发现原始代码更具可读性。
由于我不是一位经验丰富的Haskell程序员,所以我想问一下seq
以这种方式进行介绍是否是一种常见的做法,以及通常seq
在Haskell生产代码中看到该代码的频率。还是有什么技术可以避免使用seq
太频繁而仍然只使用很少的堆栈空间?
1
像您所描述的类型之类的优化几乎总是会使代码变得不太优雅。
—
罗伯特·哈维
@Robert Harvey:是否有其他技术可以使堆栈使用率保持较低?我的意思是我想我必须以不同的方式重写我的函数,但是我不知道是否存在完善的技术。我的第一个尝试是使用尾递归函数,该函数虽然有帮助,但却无法完全解决我的问题。
—
乔治