除了模式匹配的问题(我也推荐 CA McCann 的答案),您的程序可能没有您预期的效率,而且肯定比它可能的效率低。
问题在于 Haskell 的列表是简单的单链表,它们不能以方便的、O(1) 可访问的形式来携带它们的长度。Haskelllength
必须计算列表节点的数量,这需要 O(N) 时间。这意味着setelt
(由 Nicolas Dudebout 的回答提供)的直接更正版本将在每个 step扫描剩余列表,产生 O(N^2) 最坏情况下的性能,而不是可能的 O(N)。
要解决此问题,请先扫描列表以获取长度。类似于以下实现,它是 O(N) (尽管使用take
并drop
最终扫描列表的次数超过了严格必要的次数):
setelt :: Int -> [a] -> a -> [a]
setelt n ys z = front ++ z:back where
count = length ys - n
front = take count ys
(_:back) = drop count ys
最后,如果不清楚:标准的 Haskell 列表索引(由take
、drop
和使用!!
)从列表头部的 0 开始,而不是尾部的 1 (这可能是您对 , 的意图setelt
,并且已实现以上)。如果您的意图是从 0 开头,则实现更容易:
setelt n ys z = front ++ z:back where
front = take n ys
(_:back) = drop n ys
或者,更有效地:
setelt 0 (y:ys) z = z:ys
setelt n (y:ys) z = y:setelt (n-1) ys z