以下段落来自Learn You a Haskell for Great Good!
“当在长字符串上反复使用++运算符时要当心。将两个列表放在一起时(即使将单例列表附加到列表中,例如:[1,2,3] ++ [4] ),在内部,Haskell必须遍历++左侧的整个列表。在处理不太大的列表时这不是问题,但是在长度为五千万个条目的列表末尾放置内容是但是,使用:运算符(也称为cons运算符)将某些内容放在列表的开头是即时的。“
我不知道为什么Haskell必须遍历++左侧的整个列表。
答案 0 :(得分:4)
rhs(右侧)上的列表必须在lems的最后一个元素之后 。由于haskell列表是根据后继者实现的,因此您需要“到达”最后一个元素以向其添加任何内容,即,使要添加的列表成为其后继者。
如果仅存储对第一个元素的引用,这类似于以命令式语言连接单链列表。您只能追加到最后一个,但是要找到它,您需要遍历所有链接。
如果实现自己的列表,则由于语法更改而变得更加明显:
data List a = Empty | Cons a (List a)
Cons 1 (Cons 2 (Cons 3 Empty)))
要追加到这样的列表,您需要更改中间Empty
的 * 。但是,从外部(例如通过模式匹配)查看值,您只会看到Cons 1 <tail>
。在您进行评估并看到tail
等之前,Cons 2 <tail>
部分有些模糊,这是您试图避免的。
相反,前置将只是Cons 0 <the list above>
,包装整个列表而无需查看它。这就是为什么您可以写0 : [1..]
之类的东西而不能写[1..] ++ [42]
之类的东西的原因。
* 创建一个与该特定点不同的新列表。 Haskell列表(通常是值)显然是不可变的。
答案 1 :(得分:1)
Haskell中类似[3,1,5,6]
的列表如下:
3 : (1 : (5 : [6]))
,其中:
是cons函数。显然,您仍然可以在Haskell中编写类似[3,1,5,6]
的列表,但这只是花哨的语法。
在6后面添加元素非常困难,如您所见:6一直嵌套在列表的下方。为了添加项目,Haskell需要完全解构列表,然后才能添加项目,如下所示:
(++) (x : xs) otherList = x : (xs ++ otherList)
(++) [x] otherList = x : otherList
这很可能不是(++)
的实际定义,但这显示了问题。 (++)
运算符必须遍历整个最左边的列表,以便将列表中的最后一项限制为新列表,然后将所有其他项递归合并。