我在Haskell中实现了一个过滤器,即我可以从命令行调用的程序如下:
$ cat inputfile.txt | myFilter > outputfile.txt
在大约80 MB的文件上运行程序时,我得到堆栈溢出 (堆栈空间溢出:当前大小为8388608字节。)。我在cygwin下使用GHC版本6.12.3。
我认为问题来自于我在程序中使用的sort
函数,但是在我一直在寻找问题三天之后,我不知道如何解决这个问题,所以我想如果有人可以给我一个提示。
以下是有关我的计划的重要细节。
我的过滤程序将标准输入读入字符串,将其拆分为行并将每行解析为某种类型的记录Event
data Event = ...
是Ord
instance Ord Event where
x < y = ...
这样我就可以使用内置的sort
函数对事件进行排序。
分割成行并解析事件(每行一个事件)由函数
执行p :: String -> [Event]
在内部使用标准函数lines
。
我还有一个将事件分组的函数g:
g :: [Event] -> [[Event]]
g使用一些与此无关的标准;每组最多可包含4个事件。
我使用sort
对每组事件(表示为列表)进行排序(即,每个组内的所有事件都被排序),最后使用函数将所有事件组格式化为字符串
f :: [[Event]] -> String
主要功能如下:
main = interact (f . (map sort) . g . p)
如上所述,在大约80 MB的文件上运行此程序会导致堆栈溢出。
如果我用以下函数替换sort函数(一个简单的快速排序实现):
mySort :: [Event] -> [Event]
mySort [] = []
mySort (e:es) = let h = [j | j <- es, j < e]
t = [j | j <- es, e < j]
in
(mySort h) ++ [e] ++ (mySort t)
main = interact (f . (map mySort) . g . p)
我没有堆栈溢出!
如果在函数mySort
中,我将t
的定义替换为以下内容:
t = [j | j <- es, e <= j]
即。我用<
替换<=
,堆栈溢出再次出现!
所以我不知道这里发生了什么。
我看不出我已经引入了任何无限递归。我的另一个假设是,懒惰的评估可以在这里发挥作用(<=
产生比<
更大的thunk吗?)。
我有一些Haskell的经验,但我不是真正的专家所以我很乐意得到一些有用的提示,因为我过去三天一直在努力理解这一点。
答案 0 :(得分:23)
罪魁祸首是
instance Ord Event where
x < y = ...
这是定义Ord
实例的错误方法。 Ord
实例的最小完整定义定义了compare
或(<=)
中的一个。根据{{1}}和compare
所有(<=)
成员函数,Ord
的默认定义均为compare
。因此,如果您定义(<)
,这是您可以使用的唯一Ord
成员,则所有其他成员在调用时将无限循环,因为他们调用compare
,调用(<=)
,调用compare
Data.List.sort
...
compare
函数使用(<)
来确定顺序,因此它会在第一次比较时循环。您的自定义快速排序仅使用{{1}},因此可以使用。
答案 1 :(得分:1)
在尝试分析代码并获得快速结果之前 - 尝试增加堆栈大小。
使用启用RTS编译程序并指定所需的堆栈大小。
http://book.realworldhaskell.org/read/profiling-and-optimization.html