如何获得与Haskell中的有限列表连接的无限列表的最后一项?
在Haskell中,如何有效地获取与有限列表连接的无限列表的最后一个项目?
last
不起作用,它显然是从头开始迭代,所以以下从不完成:
-- let's have a list of all natural numbers,
-- with zero appended
arr = [1..] ++ [0]
-- it was fast! now get the last item, should be easy
res = last arr
编辑 :我不知道什么是Haskell的[1..] ++ [0]
的内部表示,它最初是“完全未评估”? 如果它在内部将其表示为两个(未评估)列表的“序列”,则last
函数可以立即获取最后一个项目的最后一个项目。
无论附加操作++
的内部表示是什么,它都必须符合语言定义。
Haskell 2010语言报告指定:
(++) :: [a] -> [a] -> [a]
附加两个列表,即,
[x1, ..., xm] ++ [y1, ..., yn] == [x1, ..., xm, y1, ..., yn]
[x1, ..., xm] ++ [y1, ...] == [x1, ..., xm, y1, ...]
如果第一个列表不是有限的,结果是第一个列表。
是的,你可以尝试不同的定义它,就像在内存中的一些善意的物体保持它的参数列表,响应喜欢不同的请求head
或last
以特定的方式,目标是获得法律
last (xs ++ ys) == last ys
举行; 但那不仅仅是Haskell。
对于任何表达式,你都不能找到“Haskell的内部表示”。 Haskell标准没有定义内部表示; 由编译器来选择一个。
在一个简单的实现中, [1..] ++ [0]
肯定会被表示为指向两个不同列表的thunk。 但是,无论您从结果中弹出多少元素,您总是会从第一个无限列表中获取(标准确保这一点)。 所以编译器完全可以自由地完全优化++ [0]
,因为它可以证明对结果没有任何影响。
如果实际上需要存储多个可能无限长度的列表并访问其中多个列表的头部,那么请明确指出! 例如,只需使用嵌套列表[[1..], [0]]
。
Haskell中的列表是左偏的,所以为了得到列表的最后一个元素,你必须遍历整个spine,但是定义为free monoids的列表是没有偏见的,因此
last $ fromList [1..] `append` fromList [0]
计算为0
。 但是这样的名单有他们自己的问题。
上一篇: How to get last items of infinite list concatenated with finite list in Haskell?