Haskell lisp中的副作用与非破坏性

Haskell lisp中的副作用与非破坏性,haskell,lisp,Haskell,Lisp,例如,在Mathematica程序中,为列表上执行的每个操作生成新列表的速度比列表中的就地操作(如追加、删除等)要快得多 Haskell还默认为对列表执行的每个操作提供一个新列表 我读到lisp提供了这两种功能,每次都创建新列表,或者选择在列表中进行就地操作 但我感到困惑,因为它还指出,在位有助于再次重用同一个列表,从而减少垃圾。那么,哪种方式是有效的,因为我看到两种伟大的语言说的是相反的东西 但我感到困惑,因为它还指出,就地有助于重用 再次使用相同的列表,从而减少垃圾。那么,这条路怎么走 很有

例如,在
Mathematica
程序中,为列表上执行的每个操作生成新列表的速度比列表中的就地操作(如追加、删除等)要快得多

Haskell
还默认为对列表执行的每个操作提供一个新列表

我读到
lisp
提供了这两种功能,每次都创建新列表,或者选择在列表中进行就地操作

但我感到困惑,因为它还指出,在位有助于再次重用同一个列表,从而减少垃圾。那么,哪种方式是有效的,因为我看到两种伟大的语言说的是相反的东西

但我感到困惑,因为它还指出,就地有助于重用 再次使用相同的列表,从而减少垃圾。那么,这条路怎么走 很有效,因为我看到两种很棒的语言在说些什么 相反

Haskell的主要设计目标之一是易于推理。当您的所有数据结构都是不可变的时,您将获得引用透明性。这使您的代码易于推理。这种方法的其他优点是易于并发和并行

在Mathematica中,他们似乎建议使用不变的数据结构,但也通过仿真提供可变的数据结构。虽然,我不认为这是一个伟大的设计决策,但他们认为这提供了灵活性

在Haskell中,列表不是数据结构的起点和终点。还有很多:集合、向量、映射、数组等。每个数据结构都有自己的特点。为了获得良好的性能,我建议您了解每种方法的优缺点,并根据需要使用正确的数据结构。对于最简单的需求,使用List就足够了


如果出于某种原因,您确实想要Haskell中的可变数据对象,那么您可能需要查看ST monad。

不可变数据结构允许编译器使用。 (一些狂热者甚至认为可变数据结构是拙劣编译器的支柱。:-)

可变结构(数组、列表、哈希表——所有这些都存在于Lisp中)让人们可以更轻松地完成一些事情,有时还可以让程序员对代码进行微优化,而当“”比现在更像是白日梦时,这一点也不那么愚蠢


注:将Haskell和Mathematica与Lisp进行比较是不公平的,因为它们属于不同的世代。Lisp是目前仍在使用的第二古老的编程语言(仅次于Fortran),而Haskell和Mathematica建立在30多年的CS研究基础上。

正如其他人所指出的,不变的数据结构使代码易于推理。这不仅仅适用于程序员:编译器还可以更容易地对代码进行推理

例如,考虑以下身份:

map (f . g) xs = (map f . map g) xs
如果您不知道Haskell,“map f xs”将函数f依次应用于列表xs的每个元素,从而为您提供一个新列表,“.”是将两个函数组合在一起的运算符;定义是“(f.g)x=f(gx)”

上面的恒等式不是“map”定义的一部分,但它可以通过将map和“.”的定义作为公理并进行替换来证明。它说的是,您可以将“mapf.mapg”(即列表中的两次迭代)替换为“map(f.g)”(即,一次迭代依次对每个项目执行“g”和“f”)。但这只有在假设“f”和“g”没有副作用的情况下才有效。如果他们的执行顺序很重要,那么身份就不再有效。因此,您只能在所有值都不可变的语言中进行此优化

GHC允许程序员使用声明声明这些身份。Data.List中的实际规则集更为复杂和通用,但上面的规则是它给出的规则的一个特例

因此,在Haskell中,您可以编写一长串的列表操作,如

foo = take 5 . sortBy cmp . map f . filter pred . concatMap g

并将其编译成最佳代码。值可变的语言必须在整个列表中执行这些步骤中的每一步,将结果存储在内存中,然后进入下一步。对于速度太慢和/或内存不足的大型列表,必须手动重写上述表达式,而不仅仅是让编译器为您执行此操作。

并非所有语言都是平等创建的。lisp中的列表是链表,而Mathematica和Haskell可能(?)使用了更接近数组的东西。@MicroVirus:array的性能比链表差。任何想要关闭它的人,都可以就改进这个问题提出建议。我很乐意接受建议。@MicroVirus:Haskell列表是链表,主要是因为它允许惰性地评估(可能无限!)列表。但实际上,数组的性能要比列表好得多,因为它们在内存中是连续的,这就提供了更好的缓存使用。因此,任何一种合适的语言,无论它多么喜欢列表,都会提供紧凑的数组类型。每种数据结构都有其优缺点。链表在随机插入方面优于数组,但在随机访问方面较差。我想这里最令人困惑的一点是,在每种语言中,用于实际底层数据结构的名称并不相同@leftaroundabout:谢谢,我自己对Haskell并不熟悉。我同意还有其他可用的数据结构,但我需要知道的是列表中的特定数据结构。我已经知道您在这里分享的信息。GHC运行时的设计使用分代垃圾收集:短期对象非常便宜。我知道我不应该比较它们,但似乎没有多少人考虑到它在大列表的情况下对性能的实际影响。对!这就是我谈论的SSC和程序员优化。