Lisp仍然具有其他编程语言未采用的任何特殊功能吗?


35

Lisp仍然具有其他编程语言未采用的任何特殊功能吗?

Lisp是指所有Lisp编程语言的整体。有人告诉我Lisp多么惊人,并且知道许多语言都受到Lisp的启发。但是Lisp是否仍然具有任何其他语言无法完成的专有设计功能?

我问这个问题的原因是,最近,我自己是一名业余程序员,所以我开始学习Clojure只是为了好玩,结果是我发现了很多与Lisp相关的帖子和​​评论,但只说了一件事:“ Lisp是独一无二的”,但其他现代编程语言已经采用并窃取了Lisp的许多想法,例如条件,递归和作为一等公民的功能。甚至元编程也可以用多种语言完成。

我错过了什么吗?“ Lisp还是不一样”吗?

或我很幸运,因为其他现代语言从Lisp窃取了所有的好东西,因此不必深入研究Lisp括号,而“ Lisp是不同的”。


3
分享您的研究成果对所有人都有帮助。告诉我们您尝试过的内容以及为什么它不能满足您的需求。这表明您已经花了一些时间来帮助自己,这使我们免于重复显而易见的答案,并且最重要的是,它可以帮助您获得更具体和相关的答案。另请参阅“ 如何提问”
2013年

3
@gnat Thx寻求建议,我已经更新了我的问题:)
iceX

10
一个问题是,一旦一种语言具有某种Lisp功能的子集(例如S表达式和宏),人们就会认为它是Lisp。当然,哪个会导致(根据这些人)没有非Lisp语言可以具有这些功能。

9
我猜没有其他语言可以用圆括号将所有内容分组:-)
Doc Brown

Lisp作为一个家庭可能并不是很独特,但是许多Lisp的方言(球拍,CL,Scheme,Clojure)仍然提供许多有用/独特的功能。
jozefg

Answers:


28

此类问题的经典参考是保罗·格雷厄姆(Paul Graham)的《使Lisp与众不同》。根据撰写本文时,Lisp尚不广泛使用的其余两个关键功能是:

8.使用符号树的代码符号。

9.整个语言始终可用。读取时间,编译时间和运行时之间没有真正的区别。您可以在读取时编译或运行代码,在编译时读取或运行代码,以及在运行时读取或编译代码。

注释说明了每个要点,并列出了可以使用该功能的流行语言。

8(带有9)使Lisp宏成为可能,到目前为止,它仍然是Lisp独有的,也许是因为(a)它需要那些parrens或同样糟糕的东西,以及(b)如果添加了最后的幂增量,您不能再声称发明了一种新语言,而只是设计了一种新的Lisp方言;-)

请注意,本文的最新修订时间为2002年,在过去的11年中,出现了各种各样的新语言,其中一些可能会将所有这些Lisp功能纳入其设计中。


2
这些功能不是Lisp(和直接派生的变体)所独有的,并且已经存在很长时间了。
Donal Fellows 2013年

21
@iceX:JavaScript和Lisp,Smalltalk,Self,Newspeak,APL,Factor,Forth等语言之间的区别在于,在JavaScript中,程序是“死的”。它们是文本文件。您杀死正在运行的程序,编辑文本文件,然后启动该程序的全新副本。在那些其他(所谓的“活泼”的环境中),你永远不会停止正在运行的程序,运行程序本身是一组,你操纵你处理任何其他对象以相同的方式,内存中的对象在运行时。(请注意:Clojure并非如此,但大多数年长的Lisps都是这样做的。)
Mittag

2
@ ... 但是...如果他们不能改变它...为什么还要麻烦地使用我认为是用于代码操作的S表达式...(感觉就像我掉进了一个深而黑的兔子洞一样)
iceX

4
@iceX:许多语言具有eval或相似的语言,并且相当多的语言可以进行元编程,例如Haskell的Template Haskell。关于Lisp的(可以说)独特之处是数据,代码和元代码的表示是相同的-不仅在语法上,而且实际上是一回事。
tdammers 2013年

2
@iceX Eval只是其中一部分,但不是全部。在Lisp中,您可以在编译时执行代码。您可以在读取时执行代码。是的,clojure支持Lisp的所有动态功能,它具有宏,读取器宏和eval,并且能够将REPL附加到正在运行的程序上以即时对其进行修改。
stonemetal 2013年

15

这个问题很难回答,因为某个人必须知道所有语言才能知道Lisp中没有其他语言可以使用,因此以下内容基于我所使用的语言。

在我头顶上,情况是我用任何其他语言都没有见过的。考虑“异常”,但是调用栈没有解开,调用者可以将恢复值发送到异常站点,但又不打扰处理程序和异常源之间的调用栈。公平地说,这实际上只是延续的一种特殊应用,因此Ruby和Scheme(至少)可以做到这一点。

Lisp的宏系统受益于规则性/同质性,但是Scala计划将它们作为稳定功能合并到2.12中Template Haskell声称具有类似功能。我认为与Lisp相比,它们在语法上会更加复杂,但是无论如何,都可以在编译时生成代码。

不过,考虑一下,直接构建表单只是Lisp中可用的一种宏:在其他任何地方,我都没有看到等效的编译器或阅读器宏。

某些方言(例如SBCL)保存完整的可恢复过程映像的能力很酷,但这并不是唯一的:Smalltalk数十年来一直这样做。

许多其他语言允许在返回数组时进行解构分配,但是#'values和#'multi-value-bind / let-values方法仍然似乎特定于Common Lisp和Scheme(它们仍然可以进行“常规”解构) )。Perl的'wantarray'允许函数确定它是在标量,列表还是void上下文中调用的,因此它可以以类似的方式(-ish)调整其返回值,但是我在外部看不到“ true”多个返回值Scheme / CL。

就语言功能而言,Lisp可能没有其他语言不能做的很多事情(使完整性成为事实)。但是,它一种语言,其中的代码是根据自己的数据结构表示的,这使得Big Idea™(即代码就是数据)相对易于使用。


3
Scala宏的功能远不如Lisp宏,TH宏,Scheme卫生宏等强大。在MetaLua和Converge中可以找到同样强大的系统。
SK-logic

4

经过这么多年,我认为Lisp并没有什么独有的。但是即使到了今天,在Lisps之外也找不到很多有趣的东西。我想到了几件事:

  • 具有复杂的元协议(即CLOS)的高质量对象系统并不是很受欢迎。
  • 多方法有时会在某个地方弹出,但大多数人从未听说过它们。
  • 正如其他人指出的那样,与流行的异常处理机制相比,条件系统非常复杂。
  • 语言语义(eval)的紧凑表示形式,一种定义一种语言并使其可用于直接的深度改编的授权方法(请参阅SICP)-当前流行语言的“ eval”功能根本不具有相同的属性。

最后,从Lisp中可以学到很多东西,这与语言本身无关,而是成为Lisp历史的一部分并随时间流逝的。例如Interlisp,Symbolics Genera等...如果您从未动手过Genera,请参见comp.lang.lisp 线程,肯特·皮特曼(Kent Pitman)描述了“ Emacs仅仅是Genera的Zmacs的苍白阴影”的原因-所有这些都由具有功能强大的Lisp系统,该系统是Zmacs的一部分,并在Lisp机器上运行。


我从来没有见过关于多方法的很好的解释,可以将它们与重载方法区分开来,重载方法是几乎所有现代命令式语言中的标准功能,但事实是,多方法调度是在运行时动态解析的,因此比重载方法要慢得多。在编译时解决。
梅森惠勒

它们有重要的区别。如果你在上很难找到的资源,你可以随时在这里创建一个新的问题..
席尔瓦

Julia有多种方法,而Haskell的参数多态性就像多种方法一样。有多种方法可以模拟多种语言中的多重方法。条件系统是我特别想要的东西(编辑并继续,尽管我已经在C#调试器中看到过)。
aoeu256

4

它不一定是单个功能。这是整个外观,以及某些功能集如何协同工作。

JavaScript或Java具有Lisp的许多功能(虚拟机,编译器/评估器,垃圾收集等)。但是,例如JavaScript缺少符号编程部分,缺乏数学功能(内部仅具有浮点数),缺乏错误处理,依此类推。

许多Common Lisp系统都针对一种开发方式进行了优化,该开发方式是使用各种元编程技术以各种维度扩展Lisp语言,从而逐步扩展新软件,而无需长时间重新启动软件。因此,它需要具有灵活性和可扩展性,但同时也需要具有鲁棒性。更改语言(宏基本上是用户扩展编译器的一种方式),而不会导致程序崩溃。

现在,诸如JavaScript之类的东西也用于扩展程序,通常是Web浏览器。但是大多数时候,除了一些OOP骇客之外,人们并没有使用JavaScript进行元编程。

例:

可以通过两种方式为计算机代数领域实现通用的高级数学软件:用C编写引擎,并在顶部使用专门的语言(例如Mathematica)或使用一些更高级的Lisp方言。Maclisma / Maxima常见于Lisp,标准版Lisp 减少Axiom常见于Lisp。

(也有一个或多个用Python编写的。)

提供Axiom之类的功能集的系统很少,它可以在Common Lisp之上运行。

Lisp对这些类型的应用程序具有吸引力的原因是多种功能的组合:高级基本数学(数字,比率,...),符号计算,交互式编译器等。通过在低端实现这些功能很可能获得这些东西。语言。这样,一个人将实现典型Lisp系统的50%或更多。


2

据我所知。Forth和Lisp一样容易动态,也许更是如此,因为Forth中的动态代码看起来像常规的Forth代码,而Lisp宏倾向于使用与常规Lisp代码不同的功能(至少在Clojure中,我从未在宏之外使用语法引号)并且结果,它们看上去与常规的Lisp代码完全不同。作为一个动态的Forth例子,这是在Forth中实现注释的一种方法

: (   41 word drop ; immediate
( That was the definition for the comment word. )
( Now we can add comments to what we are doing! )

1
就像Forth看起来那样有趣,我总是发现它毫无希望地变得不透明和笨拙,也许是因为它是基于堆栈的并且一切都被颠倒了。
罗伯特·哈维

2
出于好奇,“与语言的主要部分分离”是什么意思?Lisp中的宏可以完全访问在定义宏时定义的所有函数,任何函数都可用于构建宏扩展为的形式。这可能涉及从数据库和/或服务器检索到的信息。您的注释示例可以定义为:(defmacro comment(&rest body)),不是吗?
丹尼·伍兹

1
@DannyWoods我的意思是宏看起来不像常规代码。至少在clojure中,您可以从常规代码中分辨出宏代码,因为它大量使用语法引号,取消引号拼接等,这在常规代码中是不常见的。我给出的第四个示例代码看起来像普通代码,直到您看到立即为止。重读我的答案只是表达不好。
stonemetal

1
@stonemetal不用担心,但是值得注意的是,在Common Lisp或Clojure中,语法引用没有特定于宏的内容。在常规函数定义中使用反引号表达式有时会很方便,并且可以使用纯列表手动构建宏主体(尽管您只需执行一次或两次即可确定语法引用是一件好事!)
Danny Woods

1
公平地说,可以通过注册自定义阅读器宏在Lisp中完成相同的操作。
fjarri 2013年

2

Lisp有许多方言,每个方言都有其自己的功能。我最喜欢的功能(不太可能被其他任何语言采用)是Interlisp的“意大利面条堆栈” 。

意大利面条堆就像一个封闭物,但是在类固醇上。它不仅保存当前函数,还保存整个上下文,直到堆栈的顶部。类似于协同例程,除了可以随意创建它们,从而形成堆栈上下文层次结构。


不知道,要检查一下,谢谢您的回答:)
iceX

7
这与Scheme的延续相同吗?
Nicola Musatti 2013年

1
@NicolaMusatti,“意大利面条堆栈”是类似于Scheme的延续的常见实现策略(可以在创建它们的函数返回后调用)。
Alex D
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.