在On Lisp(第9页)中,可以找到以下声明:
函数是Lisp程序的构建块。它们也是Lisp的构建块。在大多数语言中,+运算符是完全不同的 来自用户定义的函数。但是Lisp有一个单一的模型,功能应用程序 描述程序完成的所有计算。 Lisp +运算符是一个函数, 就像你自己定义的那些。 实际上,除了少数运营商称为特殊形式的核心 Lisp是Lisp函数的集合。什么阻止你加入这个 采集?什么都没有:如果你想到Lisp可以做的事情,你 可以自己编写,你的新功能将被视为内置的 的。
我的问题是如何使用以下特殊运算符实现+
运算符的确切实现?或者实际上有更多的运营商在使用,格雷厄姆只是不精确和戏剧化?
block let* return-from
catch load-time-value setq
eval-when locally symbol-macrolet
flet macrolet tagbody
function multiple-value-call the
go multiple-value-prog1 throw
if progn unwind-protect
labels progv
let quote
有没有办法查看这些功能的源代码?
答案 0 :(得分:6)
他并不是说每个功能都是以这些特殊形式实现的。
他说{{1}}(和其他所有功能一样)是一个功能:
+
调用它(其中(+ x y z)
是函数,+
,x
,y
参数。z
会在调用(f (g) (h))
之前同时调用g
和h
,即使f
恰好是{{1} }}。f
和+
调用它:funcall
为6。关键是这些属性不一定适用于特殊形式。 apply
不首先评估所有论点;你不能参考(let ((x #'+)) (funcall x 1 2 3))
并间接称呼它;等
当然,这仍然为“编译魔术”打开了大门。在某些时候if
必须执行低级操作,例如,如何实现数字。根据您的Lisp编译器,细节看起来会有所不同。
答案 1 :(得分:4)
cl:+
就像一个函数一样,被视为一个函数。
您无需自己定义或仅使用其他已定义的CL标准运算符定义它。 cl:+
的定义很可能使用特定于实现的内部功能。
Common Lisp有三种类型的运算符:函数,宏和特殊运算符。
标准没有详细说明它们的实施方式。有理由相信Common Lisp实现将有额外的内部运算符用于实现标准的运算符。
有一个固定数量的special operators - 尽管CL实现可能会提供额外的特殊运算符。特殊操作符不是函数,用户无法定义特殊操作符。
CL定义了一系列标准宏以及用户定义新宏的方法。未指定如何定义标准宏。
CL定义了一系列标准函数和用户定义新函数的方法。未指定如何定义标准函数。
答案 2 :(得分:3)
这里是src / code / numbers.lisp
中来自sbcl的源代码(macrolet ((define-arith (op init doc)
`(defun ,op (&rest numbers)
(declare (explicit-check))
,doc
(if numbers
(let ((result (the number (fast-&rest-nth 0 numbers))))
(do-rest-arg ((n) numbers 1 result)
(setq result (,op result n))))
,init))))
(define-arith + 0
"Return the sum of its arguments. With no args, returns 0.")
(define-arith * 1
"Return the product of its arguments. With no args, returns 1."))
答案 3 :(得分:3)
在实际层面上,您在观察到仅使用核心特殊表单来实现+
并不是特别有效时是正确的,而没有任何算术感知的低级实用程序(从那以后)在算术中,CPU往往非常好。
+
函数没有任何固有的东西可以阻止你自己定义它。在大多数语言中(C ++是另一种例外),+
将以与用户定义的函数完全不同的方式实现。两个常见原因是因为+
通常使用中缀表示法,而函数调用使用func(arg1, arg2)
表示法;并且通常不可能使用随机符号(如加号)来定义新的用户创建的函数。
另一方面,Common Lisp并没有这个限制。 +
使用与任何其他函数相同的语法结构,因此该原因不适用;同样,Common Lisp允许您在函数名称中使用许多不同的字符。
例如,这在GNU clisp
中工作正常(带有警告),而在JavaScript中没有可能做同样的事情:
(defun + (a b) (- a (- 0 b))) ; using '- to avoid having to look up other forms
答案 4 :(得分:2)
在其他语言中,Algol是最常见的,APL可能是最明显的,使用户定义的抽象与语言附带的功能和形式无法区分是非常特殊的。
因此我认为你误读了这段文字。想象一下,你想创建一个数字库,扩展数字的语言概念,可能是间隔。您创建了一个库并定义了一种创建间隔的方法,并使您的库在数量和间隔上工作。如果你有一个数学库你可以在库中使用你的类,它可以开箱即用,只要你定义了所需的所有功能。现在在大多数Algol语言中+
,/
,...不是函数而是运算符,它们有特殊的规则,因此即使C ++使运算符重载不多,其他语言也不支持生成{{1适用于您的新间隔类型。解决方案的功能显然不像语言本身的原语,因为它们是运算符。在APL中,所有基元都具有特殊符号,并且所有用户定义的基元都没有,因此所有用户定义的抽象都很容易看到,因为它们不是花哨的符号。
今天我们经常提出Java,JavaScript,C ++等新版本。这是必要的,因为这些语言没有办法在语言中抽象出自己的语法。今天的JavaScript有babel,它基本上为你提供了一种将一种语法转换为另一种语法的方法,但是它还没有提供一种功能,可以让你从语言中做到这一点。这些是Lisp几十年来所拥有的东西,而现代语言正在获得lisp功能,但有些仍然很稀疏。
我做了一个lisp语言,与第一个lisp一样缺少数字,因为我对它不感兴趣。我还必须用那种语言制作99瓶啤酒。我使用了列表和符号,制作并定义了+
,+
,-
。当你看到实际的程序时,你看不到它缺少数字。
我喜欢Guy L. Steele在98年关于extending programming languages的演讲。他是Scheme的原作者,并参与过多种语言,包括Java和Common Lisp。