我的问题很简单(也许是误导性的)。
在Common Lisp中,当我运行以下命令时,我得到相应的结果:
(eval '''boo) => 'boo
另一方面,如果我运行以下命令,我会得到一些不同的东西。
(eval (eval '''boo)) => boo
我的问题是:如果第一个命令的eval
“从变量符号中删除”两个引号并在输出处留下一个标记,那么两个嵌套{{1}的可能性如何?函数总共取三个引号?
这特别令人困惑,因为以下结果会导致错误:
eval
答案 0 :(得分:7)
'boo
是(quote boo)
的缩写。在代码中,quote
是一种特殊的形式,它可以评估它的论点,仅此而已。因此boo
。当此值传递给它的数据而不再是代码,但为了创建符号foo
,您需要quote
。
'''boo
是(quote (quote (quote boo)))
的缩写。在评估它时,它完全像以前一样,它变成(quote (quote boo))
,一个包含两个元素的列表,其中第二个元素是两个元素的列表。
由于eval
是一个函数,它首先计算参数,然后它会根据函数的作用来计算结果。因此,(quote (quote foo))
在第一次评估后变为(quote foo)
,而eval
从第二次评估中取消,留下符号foo
。
如果eval
得到符号foo
,则意味着它应该获得全局命名空间中变量foo
绑定的值。因此:
(defparameter *test* 5)
(eval '*test*)
; ==> 5
由于参数为(quote *test*)
,评估后变为*test*
。 eval
看到符号并获取值5
,这是结果。如果未绑定*test*
,则会收到错误。
(defparameter *test-symbol* '*test)
(eval *test-symbol*)
同样在这里。由于函数*test-symbol*
被评估为符号*test*
,因此这是eval
看到的内容,它会获取值5
。
(defparameter *result* (eval '''foo))
*result*
; ==> (quote foo) but often the REPL shows 'foo
(consp *result*)
; ==> t
(length *result*)
; ==> 2
(car *result*)
; ==> quote
(cadr *result*)
; ==> foo
有时我会看到初学者做'('(a) '(b))
之类的事情。这是一个错误,因为在评估时最终会将列表((quote (a)) (quote (b)))
作为数据,而这很少是意图。当使用像list
这样的函数时,参数会被评估,你需要适当引用:
(list '(a) *result* '(b))
; ==> ((a) (quote foo) (b))
答案 1 :(得分:4)
第一个问题:
Evaluating (eval '''boo)
Evaluating '''boo
Result: ''boo
Calling Function EVAL with ''boo
Function EVAL returns 'boo
Result: 'boo
第二个问题:
Evaluating (eval (eval '''boo))
Evaluating (eval '''boo)
Evaluating '''boo
Result: ''boo
Calling EVAL with ''boo
Function EVAL returns 'boo
Calling Function EVAL with 'boo
Function EVAL returns boo
Result: boo
答案 2 :(得分:3)
eval
是一个功能。在将eval
应用于它之前评估其参数。这就是为什么看起来eval
"剃掉"两个引号。一个是通过函数应用程序的隐式评估删除的,另一个是eval
应用程序本身。
但是当你唤起(eval (eval '''boo))
时,外部eval
会应用于从内部'boo
返回的值eval
。等价物是(eval ''boo)
。
当您尝试(eval 'boing)
时,会在eval
应用之前评估参数,因此eval
会尝试评估boing
并出错。
将此与eval
的宏版本进行对比,该版本在应用eval
之前未评估其参数...
? (defmacro meval (form) `(eval ',form))
MEVAL
? (meval 'foo)
FOO
? (meval '''foo)
''FOO