【发布时间】:2011-07-08 11:31:06
【问题描述】:
List 和 cons 运算符 (:) 在 Haskell 中非常常见。缺点是我们的朋友。但有时我想添加到列表的末尾。
xs `append` x = xs ++ [x]
遗憾的是,这不是实现它的有效方法。
我在 Haskell 中写了 Pascal's triangle,但我不得不使用 ++ [x] 反成语:
ptri = [1] : mkptri ptri
mkptri (row:rows) = newRow : mkptri rows
where newRow = zipWith (+) row (0:row) ++ [1]
恕我直言,这是一个可爱易读的帕斯卡三角形,但反成语让我感到厌烦。有人可以向我解释(理想情况下,为我指出一个好的教程)对于您想要有效地追加到末尾的情况,惯用的数据结构是什么?我希望这种数据结构及其方法具有近似列表的美感。或者,或者,向我解释为什么这个反成语实际上对这种情况并没有那么糟糕(如果你认为是这样的话)。
[编辑] 我最喜欢的答案是Data.Sequence,它确实具有“近乎列表般的美感”。不知道我对所需的操作严格性有何看法。欢迎提供进一步的建议和不同的想法。
import Data.Sequence ((|>), (<|), zipWith, singleton)
import Prelude hiding (zipWith)
ptri = singleton 1 : mkptri ptri
mkptri (seq:seqs) = newRow : mkptri seqs
where newRow = zipWith (+) seq (0 <| seq) |> 1
现在我们只需要 List 是一个类,这样其他结构就可以使用它的方法,比如zipWith,而不需要从 Prelude 中隐藏它,或者限定它。 :P
【问题讨论】:
-
List 不是一个类,但 ListLike 是。还有一个 Data.Sequence 实例可用。 hackage.haskell.org/package/ListLike-3.0.1
-
随机烦恼:我首先尝试写
newRow = 1 <| zipWith (+) seq (drop 1 seq) |> 1,恕我直言,通过在每一行的两端显式显示1来表达帕斯卡三角形非常漂亮。可悲的是,我收到了这个错误:cannot mix '<|' [infixr 5] and '|>' [infixl 5] in the same infix expression -
第二个
newRow非常漂亮。我使用 ZipLists 进行了一次不太成功的尝试(我正在计划更通用的东西,但它太复杂了)hpaste.org/44613/pascals_ziplist。使用she预处理器的成语方括号和一些自制的组合器,它看起来像这样:pascalsNextLine old = 1 <& (| tail' old + init' old |) &> 1知道您的这个想法是否有什么可以概括的东西会很有趣。 -
看来
|>和<|的优先级相同,所以它们不能并排。我想知道是否有办法改变它,而不会破坏其他文件,按每个文件排序。
标签: haskell performance linked-list append idioms