【发布时间】:2014-06-21 17:31:54
【问题描述】:
自从我前段时间学习 Haskell 以来,我一直看到人们 reverse 列表,只是稍后将它们反过来。下面是一个用分隔符分割字符串的函数:
splitOn ::Eq a => a -> [a] -> [[a]]
splitOn sep str = s_word str []
where s_word [] w = [reverse w]
s_word (c:cs) w = if (c == sep) then reverse w : s_word cs []
else s_word cs (c:w)
我认为原因是“缺乏”右/反向 cons 运算符,例如:
rcons xs x = xs ++ [x]
当然,rcons 的效率远低于 cons 运算符 (:)。
但上面的代码似乎通过使用reverse 引入了它自己的低效率。我想知道它是否比以下变体更有效或效率更低:
splitOn' ::Eq a => a -> [a] -> [[a]]
splitOn' sep str = s_word str []
where s_word [] w = [w]
s_word (c:cs) w = if (c == sep) then w : s_word cs []
else s_word cs (rcons w c)
这两个函数似乎实现了同样的事情。我认为第二个版本似乎更直观(尽管可能不那么聪明)。像这样使用rcons 有什么陷阱吗? (无限列表,懒惰等)
谢谢。
附:输出:
*Main> splitOn' ',' "a,b,"
["a","b",""]
【问题讨论】:
-
如果我遇到了一个我认为确实需要在两端高效consing的问题,我会使用Data.Sequence from the containers package
-
还请注意,您可以高效地编写
splitOn而无需反转或rconsing。考虑使用break (== x)。 -
希望
reverse的内部实现比天真的Haskell 实现更理智一点。它可以是一个常数时间的实现。但话又说回来,我不知道 ghc 的任何实现细节。 -
@bitmask,内置的 Haskell 列表是所有传统实现(包括 GHC)中真正的单链表。基本上,这是因为任何更高级的东西都会减慢至少一些适当使用它们的代码。如果您需要更高级的东西,可以从一个或另一个包裹中获得。