在 Racket 或 SML 等函数式语言中,我们通常在递归调用中执行列表操作(模式匹配、列表追加、列表连接......)。但是,我不确定这些操作在函数式语言中的一般实现。列表中的创建、更新或删除元素等操作是否会返回列表的全新副本?我曾经在一本书中读到一个关于函数式编程缺点的例子;也就是说,每次更新数据库时,都会返回一个全新的数据库副本。
我质疑这个例子,因为 FP 中的数据本质上是不可变的,因此从现有列表创建列表不应该创建一个全新的副本。相反,新列表只是基于过滤条件的对其他列表中现有对象的不同引用集合。
例如, listA = [a,b,c]
和 list B=[1,2,3]
,我创建了一个新列表,其中包含现有列表中的前两个元素,即C=[a,b,1,2]
. 这个新列表只包含对a,b,
fromA
和1,2
from 的引用B
。它不应该是新副本,因为数据是不可变的。
因此,要更新列表中的元素,只需要线性时间在列表中找到一个元素,创建一个新值并创建一个新列表,该列表与旧列表中的元素相同,但更新后的元素除外。要创建一个新列表,运行环境只需更新前一个元素的下一个指针。如果一个列表保存了非原子元素(即列表、树...),并且仅更新了其中一个非原子元素中的一个原子元素,则该过程递归地应用于非原子元素,直到原子元素如上所述更新。这是应该如何实施的吗?
如果有人在每次从现有列表/添加/更新/删除/带有元素创建列表时创建列表的整个深层副本,那么他们做错了,不是吗?
还有一点是,当程序环境更新时(即为一个新变量添加一个新的键/值条目,以便我们以后可以参考),它并没有违反函数式编程的不可变属性,是吗?