Common lisp X in(LET((X…)是一个完全丰满的符号吗?

Common lisp X in(LET((X…)是一个完全丰满的符号吗?,common-lisp,Common Lisp,或者换句话说:CL中的变量是否可能不是符号的一部分 (let ((a 10) (b 'a)) (list a b)) ; ==> (10 a) 我想我可能对CL中的变量有着深刻的误解 我一直认为CL没有变量,只有符号,符号(除其他属性外)有一个名称和一个值单元格(即变量)。 当有人说“变量x的值为42”时,我认为它是“名为x的符号的值单元格存储值42”的缩写 但这可能是错误的 当我输入 > (let ((a 42)) (type-of 'a)) SYMBOL ;

或者换句话说:CL中的变量是否可能不是符号的一部分

(let ((a 10) (b 'a))
  (list a b))
; ==> (10 a)
我想我可能对CL中的变量有着深刻的误解

我一直认为CL没有变量,只有符号,符号(除其他属性外)有一个名称和一个值单元格(即变量)。
当有人说“变量
x
的值为42”时,我认为它是“名为
x
的符号的值单元格存储值42”的缩写

但这可能是错误的

当我输入

> (let ((a 42))
       (type-of 'a))
SYMBOL
; caught STYLE-WARNING:
;   The variable A is defined but never used.
本例中的词法变量
a
是否是一个完全充实的符号,其值单元格已设置为42


由于警告
变量A已定义但从未使用过,因此建议使用另一种方式,并且词法变量似乎与符号
A
不同,其形式如下
(“A”的类型)

值单元格用于动态(也称为“特殊”)变量,而不是词法变量。词法变量是源代码中的符号,但它们与符号没有任何运行时关系(调试器内部使用除外)

所以如果你写:

(let ((a 42))
  (declare (special a))
  (print (symbol-value 'a)))

它可以工作,因为声明使其成为一个动态变量,然后您可以访问函数单元格中的值。

Common Lisp有两种数据类型,它们对计算有特殊意义:

  • cons单元格/列表->用于Lisp源代码中,列表是Lisp表单
  • 符号->用作各种用途的名称
如果您想在Lisp代码中使用它们作为数据,那么必须引用它们

这两种语言都在Lisp源代码中使用,但一旦编译代码,它们可能会消失

变量在源代码中是以符号的形式编写的,但在编译代码中,当它们是词汇变量时,它们可能会消失

使用SBCL的示例:

档案

(defun test (foo)
  (+ foo foo))
现在我们做到了:

CL-USER> (proclaim '(optimize (debug 0)))  ; the compiler saves no debug info
; No value
CL-USER> (compile-file "/tmp/test.lisp")
; compiling file "/private/tmp/test.lisp" (written 23 MAY 2017 09:06:51 PM):
; compiling (DEFUN TEST ...)

; /tmp/test.fasl written
; compilation finished in 0:00:00.013
#P"/private/tmp/test.fasl"
NIL
NIL
CL-USER> (find-symbol "FOO")
FOO
:INTERNAL
编译器已读取源代码并创建了一个已编译的FASL文件。我们看到符号
FOO
现在位于当前包中。
FOO
在源代码中命名变量

现在退出SBCL并重新启动它

让我们加载机器代码:

CL-USER> (load "/tmp/test")
T
CL-USER> (find-symbol "FOO")
NIL
NIL

不再有符号
FOO
。也不可能使用符号
FOO
检索变量
FOO
的词法值。没有映射(类似于某种显式词法环境)从符号到词汇值。

您没有检查绑定变量
a
或其值的类型,而是检查与
表单中变量同名的文字常量符号的类型:

(let ((a 42))
  (type-of 'literal-symbol))
; ==> symbol (since 'literal-symbol evaluates to a symbol, just like 'a does)
要检查绑定
a
的值类型,请在不使用文字引号的情况下执行此操作:

(let ((a 42))
  (type-of a))
; ==> (integer 0 281474976710655)
在这里,您实际上检查了let界限值的类型,它是一个整数。
42
是一个数字而不是一个符号,这让人惊讶吗

(let ((a 10) (b 'a))
  (list a b))
; ==> (10 a)

变量
a
和引用的literal
'a
不一样。它们只是在显示时看起来一样,但
'a
是数据,
a
是代码。在CL中,编译器可能在内部使用列表和符号,但其执行时的情况完全取决于实现,在大多数实现中,编译器不会使用列表和符号hey stack allocate when can,计算堆栈分配变量的代码将替换为从堆栈中提取索引值的代码。CL有一个
反汇编
函数,如果您在SBCL中检查来自某个对象的输出,您将看到它比原始lisp sourc更类似于C编译器的输出e、

这是否意味着由
defun
lambda
let
等创建的词法变量看起来是符号,但一旦编译,事实上就不是了?它们只是源代码中的符号,就像函数调用是源代码中的列表一样。在编译时,它们都会变成机器代码和词法变量s只是堆栈位置。