为什么用功能语言列出选择的数据结构?


45

大多数功能语言都使用链表作为其主要的不变数据结构。为什么要列出,而不要列出树?树还可以重用路径,甚至模型列表。



10
@gnat-这不是该问题的重复项。该问题的公认正确答案本质上是“因为不可变的链表允许在更新列表和原始列表之间共享尾部”,该答案被指出为该问题背景的一部分...
Jules

9
需要澄清的一点是,“列表”(抽象编程概念)与“链接列表”(该概念的特定实现)不同,就像编程语言的规范与其实现不同。问题“为什么功能语言将列表(抽象编程概念)用作主要数据结构?” 与“为什么功能语言X,Y和Z的常见实现为什么将链接列表作为其主要数据结构?”这一问题有微妙的区别,但从根本上却有很大的不同。
RM

我Scala Vector(以树的形式实现)比List stackoverflow.com/questions/6928327/稍微偏爱。实际上,大多数人仍然使用List(从我所看到的)。
Akavall

我在Scala上了一些“函数式编程”课程,并使用了很多树木。只是列表更简单一些。树用于性能问题。您可以创建重用部分老树的不可变树,就像将元素添加到不可变列表中一样。
Borjab

Answers:


56

因为列表比树更简单。(您可以通过列表是简并树的事实来简单地看到这一点,其中每个节点只有一个孩子。)

缺点列表是任意大小的最简单的可能递归数据结构。

盖伊·斯蒂尔(Guy Steele)在Fortress编程语言的设计过程中认为,对于未来的大规模并行计算,我们的数据结构和控制流都应为具有多个分支的树形,而不是像现在这样线性。但是就目前而言,我们大多数核心数据结构库在设计时都考虑了顺序的迭代处理(或尾递归,这并不重要,它们是同一回事),而不是并行处理。

请注意,例如在Clojure中,其数据结构是专门当今的并行,分布式,“多云”世界设计的,甚至数组(在Clojure中称为向量),可能是所有数组中最“线性”的数据结构,实际上实现为树木。

因此,简而言之:缺点列表是最简单的持久性递归数据结构,无需选择更复杂的“默认”。当然,其他选项也可以作为选项使用,例如Haskell具有数组,优先级队列,映射,堆,挖掘,尝试以及您可能想象的所有内容,但是默认值为简单的缺点列表。


10
是的,Clojure向量是作为树实现的,但是需要注意的是它们是哈希数组映射的trys,而不是您的标准binary data Tree a = Leaf a | Branch a (Tree a) (Tree a)。这加强了您的“简单性”论点。
wchargin

1
FWIW Clojure的持久向量被实现为(如@wchargin指出的那样复杂的)树,用于快速(具有大底数的对数)访问和更新任意元素,而不是真正用于并行操作本身(不变部分在某种程度上照顾了这一点)学位)。其他FP语言在想要两者(例如Haskell Sequence或Scala )时都做出相同的选择(有时使用不同种类的树)Vector,但仅在需要读取时才使用树,因为它们可以在真正的恒定时间内实现(例如Haskell Vector或通过.Net的F#ImmutableArray
badcook

1
例如,pmap对Clojure中的向量执行ping操作仍会顺序访问每个元素;向量的树形结构通常对最终用户不可见。
badcook

5

实际上,这些列表树木!您的节点具有两个字段carcdr,其中可以包含更多此类节点或叶子。唯一的东西,它使那些树成列表,是对公约解释cdr链接作为一个线性表的链接到下一个节点,而car作为当前节点的值链接。

就是说,我想函数式编程中链表的流行与迭代中递归的流行有关。当您当前唯一的循环构造是(tail-)递归时,您需要易于使用的数据结构。和链接列表非常适合此操作。


5
这取决于语言。当然,您可以使用con单元以类似LISP的方式实现树,但是例如在Haskell中,您将需要一个完全独立的结构。还要注意的是最具功能性的语言有很多比尾递归循环结构。例如,Haskell核心库提供折叠(左右),扫描,对树的遍历,对地图的键和值的迭代以及许多其他更专业的结构。当然,它们是在后台递归实现的,但是用户甚至不需要考虑这一点就可以使它们起作用。
Jules

@Jules然而,函数式编程是受LISP之类的语言开发并受到高度影响的。显然,可以通过在后台使用数组来提高所有列表迭代的效率,或者添加隐藏列表本质的语法糖,但是纯函数式编程可以做到,而不能做到。同样,Haskell是一种相当新的语言(比LISP早32岁),它在纯函数样式中添加了很多其他想法,语法糖等。我认为,通过判断Haskell来判断函数式编程有点像通过判断
Thermomix

2
@cmaster在Haskell年龄较小的时候,已经27岁了,并且影响了许多语言(包括Python,Java和C#,仅举几例有影响力)。用LISP判断功能性编程就像用ALGOL判断命令式编程一样,两者相距很远,直到变得不可识别。好。Lisp可以说仍然很重要,但是我不会认为它是“主流”,并且会错过很多后来的见解,包括ML类型。
Maciej Piechotka

1
如果您想触摸整棵树,则无法递归或无显式堆栈地迭代处理尾部的单链接树,因此我认为尾部递归与它无关。
k_g

@MaciejPiechotka Python,Java和C#都不能被视为功能语言,它们是必不可少的,并添加了一些受功能编程启发的功能。更改状态后,您将牢牢置于命令式而非函数式编程的领域。但是,我同意您的看法,LISP绝对不是主流。
cmaster
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.