【问题标题】:Haskell recursive function without stack overflow没有堆栈溢出的Haskell递归函数
【发布时间】:2012-07-08 22:01:56
【问题描述】:

我有一个递归函数,它索引一个纺织品,如果我将它用于巨大的文本文件,我会得到一个堆栈空间溢出。我想因为我把递归部分放在 let 部分我可以避免这个堆栈空间溢出,但我仍然得到它。使用此函数避免堆栈空间溢出的最佳方法是什么?

--lines to Map

parseLinesToWordEntryMap :: Int -> [String] -> M.Map Word [TextLocation] -> (M.Map Word [TextLocation])
parseLinesToWordEntryMap lineNumber [] wordEntryMap  = wordEntryMap
parseLinesToWordEntryMap lineNumber (x:xs) wordEntryMap =
    let
         lineNumber' = lineNumber-1
         wordEntryMapRec = parseLinesToWordEntryMap lineNumber' xs wordEntryMap
    in
         parseLineToWordEntryMap lineNumber x wordEntryMapRec

【问题讨论】:

  • 了解parseLineToWordEntryMap 的定义会有所帮助

标签: haskell recursion stack-overflow tail-recursion


【解决方案1】:

你所拥有的基本上是一个正确的折叠,

parseLinesToWordEntryMap lineNumber xs wordEntryMap
    = foldr update wordEntryMap (zip [lineNumber, lineNumber - 1 .. ] xs)
      where
        update (num,x) wordMap = parseLineToWordEntryMap num x wordMap

因此,如果parseLineToWordEntryMap 在其Map 参数中是严格的(对于Map 参数来说是相当典型的),则在到达列表末尾之前什么都不能做,然后返回到开头构建结果的列表。

如果可能的话,您应该以相反的方式使用输入,使用左折叠,并确保折叠函数具有正确的严格性,这样就不会构建大的 thunk。

对于更具体的建议,我们需要查看更多代码。

【讨论】:

  • parseLineToWordEntryMap 是这个函数: Int -> String -> M.Map Word [TextLocation] -> M.Map Word [TextLocation] 我目前正在研究 foldl 但不知道如何使用它为我的功能,你有什么想法吗?
  • 我需要知道函数做什么,它是如何实现的。我怀疑它只是将行号添加到与String 关联的[TextLocation] 中(如果尚不存在,则将String 插入Map)。然后很容易将其转换为左折叠。但我宁愿在不了解情况的情况下进行更多猜测。
  • 从 Daniel Fischer 的版本开始,您可以用 foldl'(Data.List 中的严格版本)替换 foldr,这需要翻转 update 定义中的参数。然后需要研究他关于严格性的其他建议。编辑:我正在添加一些猜测,现在我看到他同时发表了评论。
  • @Daniel 你的猜测是对的,我通过 BitBucket 给你发了一条消息
  • @LeonS 实际上,这里需要左折叠。我现在正在重写。
猜你喜欢
  • 2019-07-08
  • 2015-08-05
  • 1970-01-01
  • 2017-10-20
  • 1970-01-01
  • 2019-08-07
  • 2018-03-25
  • 2011-02-26
相关资源
最近更新 更多