Lisp Quoting感到困惑

Kon*_*itz 3 lisp eval quote

我有一个关于评估lisp中列表的问题.

为什么(a)(+ a 1)不评估,

(defun test (a) (+ a 1))
Run Code Online (Sandbox Code Playgroud)

就像(print 4)这里没有评估一样

(if (< 1 2) (print 3) (print 4))
Run Code Online (Sandbox Code Playgroud)

(print (+ 2 3))在这里评估

(test (print (+ 2 3)))
Run Code Online (Sandbox Code Playgroud)

它们与标准库函数有关吗?我可以在我的lisp程序中定义类似的函数吗?

dby*_*rne 6

if并且defun是宏.宏将表单扩展为更长的代码.在扩展时,不会评估宏的参数.

当你尝试编写一个函数,但因为你需要实现一个自定义的评估策略而挣扎时,它是一个强烈的信号,你应该写一个宏.

免责声明:根据您所使用的是什么样的口齿不清的,ifdefun可能在技术上被称为"特殊形式",而不是宏,但延迟评价的概念仍然适用.


Kaz*_*Kaz 5

您可能知道,Lisp复合形式通常是从外部处理的.您必须在最外层嵌套的第一个位置查看符号以理解表单.该符号完全决定了表单的含义.

;; Common Lisp: define a class A derived from B and C
(defclass a (b c) ())

;; Common Lisp: define a function of two arguments
(defun a (b c) ())

;; add A to the result of calling function B on variable C:
(+ a (b c))
Run Code Online (Sandbox Code Playgroud)

传统上,Lisp方言将表格分为运算符表单和函数调用表单.运算符表单具有完全任意的含义,由编译或解释该函数的代码片段确定(例如,评估只是简单地递归所有函数调用的参数形式,并将结果值传递给函数).

从早期的历史来看,Lisp已经允许用户编写自己的运营商.存在两种方法:解释运算符(历史上称为fexprs)和编译称为宏的运算符.两者都围绕着一个函数的概念,该函数接收未评估的形式作为参数,以便它可以实现自定义策略,从而扩展评估模型的新行为.

fexpr类型的操作被简单地切换在运行时的形式,与环境对象与它可以查找变量和这样的值一起.然后,该运算符遍历表单并实现该行为.

宏操作符在宏扩展时传递给表单(通常在读取顶级表单时,就在它们被评估或编译之前).它的工作不是解释表单的行为,而是通过生成代码来翻译它.即宏是一个迷你编译器.(生成的代码可以包含更多的宏调用;宏扩展器将负责这一点,确保所有宏调用都被抽取.)

这种fexpr做法失宠了,很可能是因为效率低下.它基本上使编译不可能,而Lisp黑客重视编译.(早在1960年左右,Lisp就已经是一种编译语言.)这种fexpr方法对词汇环境也很不利; 它需要fexpr能够对应于其调用形式的变量绑定环境,这是一种功能,这是一种词法范围不允许的封装违规.

宏编写稍微困难一些,并且在某些方面比fexprs更不灵活,但是对于宏观编写的支持在Lisp中从1960年代到70年代得到了改进,使其尽可能接近.Macro最初收到了整个表单,然后必须自己解析它.宏定义系统开发成了一些东西,它提供了带有参数的宏函数,这些参数在易于理解的部分中接收破坏的语法,包括语法的一些嵌套方面.还开发了用于编写代码模板的反引用语法,使得表达代码生成变得更加容易.

所以要回答你的问题,我怎么能像我一样写这样的表格呢?例如,如果:

;; Imitation of old-fashioned technique: receive the whole form,
;; extract parts from it and return the translation.
;; Common Lisp defmacro supports this via the &whole keyword
;; in macro lambda lists which lets us have access to the whole form.
;;
;; (Because we are using defmacro, we need to declare arguments "an co &optional al",
;; to make this a three argument macro with an optional third argument, but
;; we don't use those arguments. In ancient lisps, they would not appear:
;; a macro would be a one-argument function, and would have to check the number
;; of arguments itself, to flag bad syntax like (my-if 42) or (my-if).)
;;
(defmacro my-if (&whole if-form an co &optional al)
  (let ((antecedent (second if-form))   ;; extract pieces ourselves
        (consequent (third if-form))    ;; from whole (my-if ...) form
        (alternative (fourth if-form)))
    (list 'cond (list antecedent consequent) (list t alternative))))

;; "Modern" version. Use the parsed arguments, and also take advantage of
;; backquote syntax to write the COND with a syntax that looks like the code.
(defmacro my-if (antecedent consequent &optional alternative)
   `(cond (,antecedent ,consequent) (t ,alternative))))
Run Code Online (Sandbox Code Playgroud)

这是一个合适的例子,因为最初的Lisp只有cond.if麦卡锡的Lisp中没有.那个"语法糖"是后来发明的,可能就像一个宏观扩展到了cond,就像my-if上面一样.