哈斯克尔与里斯普的哲学差异

2020-08-03 04:43:46

Lisp(例如Common Lisp、Emacs Lisp)和Haskell的哲学上的一个不同之处在于,后者自由地使用许多完成单个任务的微小函数。这就是所谓的可组合性,或UNIX哲学。在Lisp中,过程倾向于接受配置其行为的许多选项。这被称为整体主义,或者像厨房水槽或瑞士军刀那样的程序。

哪一个更好,可以在另一个帖子里讨论。我只想举出一个简单的例子,那就是在哲学和实践上确实是有区别的。在编写了我的相当一部分的Emacs Lisp(和一小部分Common Lisp;我维护了Common Lisp系统)和我的相当一部分的Haskell之后,我认为我可以做出判断了。

完全公开:我们只看一些任何人都能理解的琐碎例子,暗示这些例子代表了用这些语言编写软件的一般方式(未经证实,但断言)。

任何背景的程序员都应该很容易熟悉的一个例子是处理列表。例如,CL有Remove-If-Not过程。其文档签名如下:

给出一个问题语句“从列表中取出满足谓词p的所有元素(前三个除外),只取其中的前五个”,在Common Lisp中,您可以非常简洁地表示为:

无论您了解Haskell还是Lisp,区别都应该是显而易见的,那就是在Lisp代码中,函数执行一些行为并接受参数来配置它们。在Haskell代码中,我们使用三个不同的函数来完成一项任务:

那个。操作符将函数组合在一起,就像UNIX中的管道一样。我们可以在UNIX中表达这一点,如下所示:

就像UNIX中的管道一样,当组合在一起时,这些函数足够聪明,可以很好地执行-我们不会遍历整个列表并每次都生成一个新列表,每个项目都是按需生成的。事实上,由于流融合,代码将被编译成一个快速循环。

如果我们想要不满足谓词的内容,我们只需再次使用not:

在Common Lisp中,组合有一点冗长,因为即使使用过,也很少使用,因此有另一个函数可以实现这一点:

(可能更灵活的方法是对Remove-if函数使用:not关键字参数。)。

在Lisp中,这种厨房水槽最病态的例子是众所周知的循环宏。

问题:获取所有小于5的元素,然后只获取该集合中的偶数元素。

在Haskell中,这同样适用于可以融合的矢量库、文本库和字节库。融合主要是一个纯度优势-如果您知道n个循环不会产生副作用,则可以将它们融合到一个循环中。这样的优势也可以应用于其他纯语言,如Idris、PureScript或ELM。