(列表1 2 3 4)和'(1 2 3 4)之间的区别?

时间:2018-05-21 14:54:34

标签: list lisp common-lisp

这是我的代码:

(format t "~a~%" (list 1 2 3 4))
(format t "~a~%" '(1 2 3 4))
(format t "~a~%" (remove-if-not #'evenp (list 1 2 3 4)))
(format t "~a~%" (remove-if-not #'evenp '(1 2 3 4)))

这是输出:

$ clisp bar.lisp 
(1 2 3 4)
(1 2 3 4)
(2 4)
(2 4)

我的问题:

  1. 两种语法之间有什么区别:(list 1 2 3 4)'(1 2 3 4)
  2. 使用一种语法比使用另一种语法有什么好处吗?

2 个答案:

答案 0 :(得分:3)

似乎返回绝对相同结果'(1 2 3 4)的{​​{1}}和(list 1 2 3 4)之间的差异是不可见的,因为Lisp中的数字会对自己进行评估。

而不是数字采用符号或表达式:

(1 2 3 4)

现在你清楚地看到了差异:(list (+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)) ;; returns/evaluates to: (3 5 7 9) ;; each of the arguments in a list gets evaluated. ;; while: '((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)) ;; equals to: (quote ((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5))) ;; returns/evaluates to: ((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)) ;; arguments of list not evaluated ;; since `quote` means: take the argument as data - unevaluated. 扩展到(因此是语法糖)'(1 2 3 4)特殊形式,而(quote (1 2 3 4))是的功能即可。 Lisp中的函数评估每个参数但是特殊表单不会评估每个参数。对于(list 1 2 3 4)quote的参数不会被评估。

现在您看到,quoteabc之前未定义,

d

有效,因为没有评估b c d!

但是这个:

'(a b c d) 
;; returns: (A B C D)

导致错误:

(list a b c d)

因为*** - SYSTEM::READ-EVAL-PRINT: variable A has no value The following restarts are available: USE-VALUE :R1 Input a value to be used instead of A. STORE-VALUE :R2 Input a new value for A. ABORT :R3 Abort main loop abc都未定义,但Lisp解释器会尝试评估它们,因为它们是函数参数。

但是你仍然可以通过引用每个参数来使用函数d获得(A B C D) - 从而使它们评估它们的符号名而不是Lisp解释器来查找它们未定义的值:

list

注意:有趣的是,不是在所有语言中,函数参数都会被评估,因为它们是函数参数。虽然Python在输入和评估函数体之前评估所有类似于Lisp 的函数参数,但R不会。

因此,函数参数的评估是一种特定于Lisp的方法来处理它的函数参数。 (但它与大多数其他语言共享 - 我只想说函数参数的评估不是一般规则)。这也是Lisp宏(和特殊形式)和Lisp函数之间的根本区别。在Lisp宏(和特殊形式)中,您可以指定在宏体中评估哪些函数参数,哪些不在。这样您就可以完全控制任何宏参数的评估。在Lisp函数中,默认情况下,在进入函数体之前首先计算所有参数。

这也是你在Lisp中学习宏(指定特殊形式)的原因之一。 (list 'a 'b 'c 'd) ;; now it works - though a b c d are not defined yet: (A B C D) quote一起实际上是所有宏的母亲。任何listbackquote操作都可以由unquotequote表示(尽管对于人类读者来说看起来更糟糕)。你可以想象,人们可以长时间思考这个话题。而你的问题直接涉及使Lisp如此迷人的内心和本质。

答案 1 :(得分:1)

不同之处在于创建列表的时间。一个由 reader 创建,另一个在运行时创建。

读者负责将您的文本文件转换为代表代码的数据结构。这个数据结构恰好是列表;这是Lisp(LISt Processing)的想法。

当读者阅读文本 (foo bar)时,它会创建一个包含两个元素的列表,即符号foobar。然后编译,i。即已转换为函数调用(或其他调用,但不允许在此处转移),其中foo命名的函数使用bar命名的变量的值进行调用。 / p>

有一个特殊的运算符告诉编译器执行此转换:quote。当编译器遇到列表(由阅读器构建)(quote (foo bar))时,它会使用quote 字面上的“受保护”,i。即正好由读者构建的列表(foo bar)

撇号'quote的简写,因此'(foo bar)读为(quote (foo bar))

因此,表单'(1 2 3)正是您在文本文件中写入的列表,正如读者所读到的那样。这称为文字列表

另一方面,(list 1 2 3)是具有三个参数的函数list的正常函数调用。只要在运行时执行此代码,它就会创建这些参数的新列表。

只有在文字列表不变的情况下才应使用它。例如,在创建多维数组时,您可能知道它的大小始终相同(可能是问题的内在因素),因此您编写(make-array '(3 5))。如果您想使其可配置,请对其进行参数化:(make-array (list width height))

您绝对必须避免的一件事是修改文字数据。