gpt4 book ai didi

lisp - Uninterned symbols 符号

转载 作者:太空宇宙 更新时间:2023-11-03 18:34:08 25 4
gpt4 key购买 nike

Common lisp 有一些我无法理解的地方。

假设我正在编写一个与此类似的宏:

(defmacro test-macro () 
(let ((result (gensym)))
`(let ((,result 1))
(print (incf ,result)))))

我能做到

> (test-macro)
2
2

现在我想看看它是如何展开的

> (macroexpand-1 '(test-macro))
(LET ((#:G4315 1)) (PRINT (INCF #:G4315))) ;
T

好的。有使用 gensym 生成的独特符号,这些符号被打印为 uninterned。

据我所知,uninterned 符号是求值器不会在内部创建符号数据绑定(bind)的符号。

因此,如果我们宏扩展到该形式,(incf#:G4315) 应该会出现错误。为了测试这一点,我们可以在 REPL 中评估该表单:

> (LET ((#:G4315 1)) (PRINT (INCF #:G4315)))
*** - SETQ: variable #:G4315 has no value

那么为什么扩展到这个字符串的宏可以完美地工作而表单本身却不能呢?

最佳答案

符号可以驻留在包中,也可以不驻留。 驻留在包中的符号可以被查找和找到。无法在包中查找 uninterned 符号。一个包中只能有一个特定名称的符号。只有一个符号CL-USER::FRED

你写:

So as far as I know the uninterned symbols are the symbols for which the evaluator does't create symbol-data binding internally.

这是错误的。 Uninterned symbols 是在任何包中都不是interned 的符号。否则他们完全没问题。 interned 表示在包的注册表 中为其符号注册

s-expression reader 确实使用符号名称和包在阅读 期间识别符号。如果没有这样的符号,它将被保留。如果有,则返回这个。

读者确实在当前包中按名称查找符号:

 (read-from-string "FOO") -> symbol `FOO`

第二次:

 (read-from-string "FOO") -> symbol `FOO`

它始终是相同的符号 FOO

 (eq (read-from-string "FOO") (read-from-string "FOO"))  -> T

#:FOO 是名称为 FOO 的非内部符号的语法。它不存在于任何包中。如果读者看到这个语法,它会创建一个新的 uninterned 符号。

 (read-from-string "#:FOO") -> new symbol `FOO`

第二次:

 (read-from-string "#:FOO") -> new symbol `FOO`

两个符号不同。它们具有相同的名称,但它们是不同的数据对象。除了包之外,没有其他符号注册表。

 (eq (read-from-string "#:FOO") (read-from-string "#:FOO"))  -> NIL

因此在您的情况下 (LET ((#:G4315 1)) (PRINT (INCF#:G4315))),未实习的符号是不同的对象。第二个是不同的变量。

Common Lisp 有一种打印数据的方法,因此在打印/读取过程中可以保留标识:

CL-USER 59 > (macroexpand-1 '(test-macro))
(LET ((#:G1996 1)) (PRINT (INCF #:G1996)))
T

CL-USER 60 > (setf *print-circle* t)
T

CL-USER 61 > (macroexpand-1 '(test-macro))
(LET ((#1=#:G1998 1)) (PRINT (INCF #1#)))
T

现在您看到打印的 s 表达式的第一个符号有一个标签 #1=。然后它稍后引用相同的变量。这可以被读回并保留符号标识 - 即使读者无法通过查看封装来识别符号。

因此宏创建了一个表单,其中只生成一个符号。当我们打印该表格并想读回它时,我们需要确保未保留符号的身份得到保留。使用 *print-circle* 设置为 T 的打印有助于做到这一点。

问:为什么我们使用 GENSYM(generate symbol)在宏中使用 uninterned generate symbols?

这样我们就可以拥有独特的新符号,这些符号不会与代码中的其他符号发生冲突。他们通过函数 gensym 获得一个名字——通常在末尾有一个计数。由于它们是未驻留在任何包中的全新符号,因此不会有任何命名冲突。

CL-USER 66 > (gensym)
#:G1999

CL-USER 67 > (gensym)
#:G2000

CL-USER 68 > (gensym "VAR")
#:VAR2001

CL-USER 69 > (gensym "PERSON")
#:PERSON2002

CL-USER 70 > (gensym)
#:G2003

CL-USER 71 > (describe *)

#:G2003 is a SYMBOL
NAME "G2003"
VALUE #<unbound value>
FUNCTION #<unbound function>
PLIST NIL
PACKAGE NIL <------- no package

关于lisp - Uninterned symbols 符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13987064/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com