Haskell支持一些用于递归列表的基本操作,例如head
,tail
,init
和last
。我在内部想知道Haskell如何表示其列表数据?如果它是单链接列表,则随着列表的增长,init
和last
操作可能会变得昂贵。如果它是一个双向链表,那么所有四个操作都可以非常容易地进行 O(1)
,尽管会牺牲一些内存。无论哪种方式,对我来说都很重要,所以我可以编写适当的代码。 (尽管,函数式编程的精神似乎是“问它是做什么,而不是它是如何做的”)。
答案 0 :(得分:28)
列表表示为......单链表。定义如下:
data [] a = [] | a : [a]
你可以写成:
data List a = Empty | Cons a (List a)
内存布局完全由此定义。
所以你最终得到这样的东西:
因此head
在此结构上 O(1),而last
或(++)
O(n) < / p>
Haskell中的数据结构没有神奇之处 - 它们的直接定义完全清楚了复杂性(模数懒惰)。如果您需要不同的复杂性,请使用不同的结构(例如IntMap,Sequence,HashMap,Vector等)......
答案 1 :(得分:14)
Haskell列表是单链接的,因此cons
,head
和tail
为O(1),而init
和last
为O( ñ)。
如果您需要更好的性能,请考虑使用Data.Sequence中的Seq
类型,该类型提供对列表两端的O(1)访问。在内部,它使用2-3 finger trees。