【发布时间】:2022-02-06 22:04:42
【问题描述】:
我正在尝试完成 Haskell 九十九题中的第 8 题,但是我在理解为什么我的函数的列表结果排序错误时遇到了问题。
compress 函数的目的是从输入列表中消除任何重复的字母,并按照它们在输入列表中首次出现的顺序输出包含唯一字母的另一个列表。
这是我的压缩功能代码:
compress l = foldr f [] l where f a b = if a `elem` b then b else a : b
当重复的字母彼此相邻时,它可以正常工作,因此 \"aaaabbb\" 输出 \"ab\" 这是正确的,但是当重复的字母被另一个字母分隔时,它会更改其在输出中的顺序,因此 \"aba\"输出 \"ba\" 而预期输出是 \"ab\"。
即使在为 foldr 写出堆栈跟踪时,我似乎也得到了预期的输出,但是当在 GHCI 中使用诸如 \"aba\" 或 \"abca\" 之类的输入运行代码时,我得到了不正确的结果。是什么导致了这种行为?为什么当重复的字母被不同的字母分隔时,输出的顺序会改变?
-
b是尾巴被折叠,所以a `elem` b只对最后的在字符串中出现a。使用\"aaaabbb\",它仍然是添加到结果中的每个字符的最后一次出现;最后一次出现恰好与第一次出现在同一个“集群”中。 -
一个低效的剩下有效的折叠将是
compress = foldl (\\acc x -> if elem x acc then acc else acc ++ [x]) []。请参阅stackoverflow.com/questions/6172004/writing-foldl-using-foldr 将compress从foldl转换为foldr。 -
@chepner,虽然该技术是正确的技术,但该代码不是正确的代码。这里要做的是首先编写一个高效的函数(使用递归助手),然后转换那到(右)弃牌。
foldl的形状不正确,无法很好地做到这一点。 -
我发布“错误”代码的部分原因是为了避免为 OP 编写正确的代码。这只是为了演示如何处理列表的“结束”。
-
有这个old SO answer 关于消除列表中的重复项。如果游戏规则禁止使用
Set或者你没有Ord实例,你总是可以使用另一个列表而不是Set 作为计算状态。
标签: haskell functional-programming fold