【问题标题】:C stack overflow HASKELL , while handling stringsC堆栈溢出HASKELL,同时处理字符串
【发布时间】:2021-04-04 18:23:30
【问题描述】:

我想找到一个字符串的所有可能分区到一个非空字符串列表中。

例如,如果我输入"sun", 我想创建这个输出:[["s","u","n"], ["s","un"], ["su","n"], ["sun"]].

我创建了一个简单的递归函数,但它打印出这个 overflow 错误我无法修复它,我需要帮助:

partition :: String->[[String]]

partition w = [[(head w)]:fix | fix <- partition (tail w)]
    ++[((head w):fix):fixfix | (fix:fixfix)<-partition (tail w)]

【问题讨论】:

  • 建议:试着用铅笔和纸在一个小的输入上进行评估,比如"",看看你是否能看到你的纸上正在增长什么堆栈。
  • 我认为这个真的棘手看看你什么时候不习惯懒惰和评估/强制的方式/时间 - 将你的与你前面的相同[[head w]] : 在两个列表前面..现在发生了什么? 提示:你什么时候强制head w?评估时您要做的第一件事是尝试将列表转换为 _ : _ 形式(_ 是一些 thunk),对于 ++,您首先评估左侧 - 对于列表理解,您需要 @987654330 @first ...
  • 顺便说一句:如果你启用BangPatterns (:set -XBangPatterns` in ghci) - 你会得到partition !w = ... 所想象的一些东西,我想这会很快地指出你的问题
  • 另外:每当你使用 headtail 时,你应该问问自己是否可以改用 partition (h:tl) = .. 重写它 - 遇到问题的地方更明显,而且通常更容易编写列表中的递归函数也是如此
  • @Carsten 即使经过严格的评估,这段代码也有很大的问题。

标签: list haskell combinatorics partition


【解决方案1】:

根本问题是您缺少递归的基本情况,因此您有一个无限循环。

简单的事情就是用模式匹配替换head/tail的混乱,这将解决这个问题作为一个副作用。

partition [] = [[]]
partition (w:ws) =
  [[w]:fix | fix <- partition ws] ++
  [(w:fix):fixfix | (fix:fixfix)<-partition ws]

结果证明它工作正常,有点令我惊讶。为什么我很惊讶?我认为,通过优化,GHC 将使用公共子表达式消除将其重写为

partition [] = [[]]
partition (w:ws) =
    [[w]:fix | fix <- partitionws] ++
    [(w:fix):fixfix | (fix:fixfix)<-partitionws]
  where partitionws = partition ws

那会很糟糕:它会在 ++ 中保存整个 partition ws 计算,使用大量内存。但现在看来 GHC 很聪明,不会那样做。

为了更有信心,您可以通过累积一个“延续”来解释您将如何处理您生成的每个元素,从而避免使用公共子表达式。

part :: ([[a]] -> [b]) -> [a] -> [b]
part f [] = f []
part f (w:ws) =
  part (\fix -> f ([w]:fix)) ws ++
  part (\q -> case q of
    [] -> []
    fix:fixfix -> f ((w:fix):fixfix)) ws

partition = part (:[])

由于我不知道的原因,这个版本比简单版本快几倍。


如果您不关心元素的生成顺序,则可以通过执行以下操作更简单(甚至可能更快)避免空间泄漏风险:

partition [] = [[]]
partition (w:ws) =
  [ q
  | m <- partition ws
  , q <- ([w]:m) : [(w:fix):fixfix | fix:fixfix <- [m]]]

这几乎和最简单的解决方案一样简单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 2019-07-08
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 2013-10-29
    • 2021-04-28
    相关资源
    最近更新 更多