我是否遗漏了一些关于LISP实习符号的重要事实?

时间:2011-04-12 17:09:24

标签: lisp symbols

要简短。这是我几次尝试实习并在clisp中使用符号。

 [1]> (setq sym (intern "foo"))
 |foo|
 [2]> (eq sym 'foo)
 NIL

为什么???

 [3]> (defun internup (me &optional (package *package*))
   (intern (string-upcase me) package))
 INTERNUP

 [4]> (eq 'abc (internup "abc"))
 T

可能必须要做好准备。

 [12]>(let ((abc 2))
   (eval '(+ 2 abc)))

 *** - EVAL: variable ABC has no value
 The following restarts are available:

确定

 [18]> (let ((abc 2))
 (eval '(+ 2 'abc)))

 *** - +: ABC is not a number
 The following restarts are available:

有趣。我应该在之前设置它吗。

 [14]> (setq a (internup "abc"))
 ABC

 [15]> (let ((abc 2))
 (eval '(+ 2 a)))

 *** - +: ABC is not a number
 The following restarts are available:

又错了。嗯,我必须遗漏一些关于LISP实习符号的重要事实。你能救我吗?

3 个答案:

答案 0 :(得分:3)

Eval评估 null lexical environment 中的表单,即没有词法绑定。这与符号的实习无关。

答案 1 :(得分:3)

你的问题与实习无关。

第一个问题确实是因为读者总是将符号大写,所以你需要调用(实习“FOO”)以获得与'foo相同的结果。

EVAL的问题是由于LET引入了一种在EVAL中不可见的词法绑定。如果你真的希望这个工作,你必须声明abc是特殊的,如下:

(let ((abc 2))
    (declare (special abc))
    (eval '(1+ abc)))

特殊声明将导致变量具有动态绑定,而不是词法绑定(后者意味着绑定仅限于本地词汇上下文,即在LET形式内。使用特殊声明,变量可用于任何事物从那种形式调用。)

请注意,使用特殊声明和eval是您应该非常小心的,您应该首先重新考虑使用EVAL。您实际需要使用它是非常罕见的。在大多数情况下,你实际上是在寻找lambda函数的使用。

答案 2 :(得分:2)

Common Lisp阅读器的区分大小写由可读表决定:

(readtable-case *readtable*)

通常,阅读器最初将以大写形式实习符号(除非您明确地转义字符)。因此:

(eq (intern "foo") 'foo) => NIL

(eq (intern "FOO") 'foo) => Ť

(eq (intern "FOo") 'fo\o) => Ť

您可以使用反引用语法为eval构建表单:

(let ((abc 2))
  (eval `(+ 2 ,abc)))

=> 4