Lisp 为什么会出现函数/宏二分法?
为什么Common Lisp中存在函数/宏二分法 允许使用同一名称表示宏(当在编译/评估中的函数位置找到宏时优先)和函数(例如可用于Lisp 为什么会出现函数/宏二分法?,lisp,common-lisp,Lisp,Common Lisp,为什么Common Lisp中存在函数/宏二分法 允许使用同一名称表示宏(当在编译/评估中的函数位置找到宏时优先)和函数(例如可用于mapcar)时,有什么逻辑问题 例如,将second定义为宏和函数将允许使用 (setf (second x) 42) 及 无需创建任何setf欺骗 当然,很明显,宏可以做的不仅仅是函数,因此类比是不完整的(当然,我不认为每个宏也应该是函数),但为什么要禁止它呢?如果它可能有用,为什么要让它们共享一个名称空间呢 我希望我没有冒犯任何人,但我真的没有找到一个“为什
mapcar
)时,有什么逻辑问题
例如,将second
定义为宏和函数将允许使用
(setf (second x) 42)
及
无需创建任何setf
欺骗
当然,很明显,宏可以做的不仅仅是函数,因此类比是不完整的(当然,我不认为每个宏也应该是函数),但为什么要禁止它呢?如果它可能有用,为什么要让它们共享一个名称空间呢
我希望我没有冒犯任何人,但我真的没有找到一个“为什么那样做?”的回答真的相关。。。我在寻找为什么这是个坏主意。因为没有好的用途而强加任意的限制在我看来有点傲慢(有点假设有完美的远见)
或者,允许它存在实际问题吗?因为完全相同的名称将代表两个不同的对象,具体取决于上下文。它使程序不必要地难以理解。我认为Common Lisp的两个名称空间(函数和值),而不是三个名称空间(宏、函数和值),是一种历史偶然性 早期的Lisp(20世纪60年代)以不同的方式表示函数和值:值作为运行时堆栈上的绑定,函数作为附加到符号表中符号的属性。这种实现上的差异导致了在20世纪80年代标准化CommonLisp时指定了两个名称空间。有关这一决定的解释,请参阅理查德·加布里埃尔的论文 宏(及其祖先,即不计算其参数的函数)以与函数相同的方式存储在符号表中的许多Lisp实现中。如果指定了第三个名称空间(用于宏),那么这些实现将很不方便,并且会导致许多程序的向后兼容性问题 有关FEXPR、宏和其他特殊形式的历史,请参阅Kent Pitman的论文
(注意:Kent Pitman的网站不适合我,所以我通过archive.org链接到了这些论文。)宏和函数是两个截然不同的东西:
- 宏正在使用源代码(!!!)并正在生成新的源代码(!!!)
- 函数是参数化的代码块
SECOND
是否是宏没有多大关系。在这种情况下,SECOND
作为一个宏根本没有帮助
那么,什么是问题示例?
(defmacro foo (a b)
(if (and (numberp b) (zerop b))
a
`(- ,a ,b)))
(defun bar (x list)
(mapcar #'foo (list x x x x) '(1 2 3 4)))
现在该怎么办?直观地看,它看起来很简单:在列表上映射FOO
。但事实并非如此。我猜,在设计CommonLisp时,还不清楚它应该做什么以及如何工作。如果FOO
是一个函数,那么很明显:Common Lisp从Scheme中汲取了词汇范围的一流函数的思想,并将其集成到语言中
但是一流的宏呢?在设计了CommonLisp之后,一系列的研究都进入了这个问题并对其进行了研究。但在Common Lisp设计时,没有广泛使用一流的宏,也没有设计方法的经验。Common Lisp标准化了当时已知的内容以及语言用户认为开发软件所必需的内容(基于早期使用类似对象系统的经验,对象系统CLOS有点新颖)。Common Lisp的设计目的并不是为了拥有理论上最令人愉悦的Lisp方言,而是为了拥有一个功能强大的Lisp,从而能够高效地实现软件
我们可以解决这个问题,并说,传递宏是不可能的。开发人员必须以相同的名称提供一个函数,我们将传递该函数
但是(funcall#'foo 12)
和(foo 12)
会调用不同的机制吗?在第一种情况下,函数foo
,在第二种情况下,我们使用宏foo
为我们生成代码?真正地我们(作为人类程序员)想要这个吗?我不这么认为——看起来它让编程变得更加复杂
(defmacro foo (a b)
(if (and (numberp b) (zerop b))
a
`(- ,a ,b)))
(defun bar (x list)
(mapcar #'foo (list x x x x) '(1 2 3 4)))
1> (sqrt 4.0)
2.0
2> (defmacro sqrt (x :env e :form f)
(if (constantp x e)
(sqrt x)
f))
** warning: (expr-2:1) defmacro: defining sqrt, which is also a built-in defun
sqrt
3> (sqrt 4.0)
2.0
4> (macroexpand '(sqrt 4.0))
2.0
5> (macroexpand '(sqrt x))
(sqrt x)
1> (define-place-macro foo (x) ^(car ,x))
foo
2> (macroexpand '(foo a)) ;; not a macro!
(foo a)
3> (macroexpand '(set (foo a) 42)) ;; just a place macro
(sys:rplaca a 42)
4> (define-place-macro foo (x) ^(bar ,x))
foo
5> (macroexpand '(foo a))
(foo a)
6> (macroexpand '(set (foo a) 42))
** (bar a) is not an assignable place