Sharpsign Colon 和 Gensym 之间的区别
Differences between Sharpsign Colon and Gensym
我刚刚阅读了 sharpsign 冒号 reader 宏,听起来它与 gensym
的效果非常相似
Sharpsign Colon: "introduces an uninterned symbol"
Gensym: "Creates and returns a fresh, uninterned symbol"
这么简单的测试
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {1002FF77D3}>.
CL-USER> (defparameter #:dave 1)
#:DAVE
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {100324B493}>.
很酷,所以失败了。
现在进行宏观测试
(defmacro test (x)
(let ((blah '#:jim))
`(let ((,blah ,x))
(print ,blah))))
CL-USER> (test 10)
10
10
CL-USER>
很好,所以它可以像 gensym 一样使用。
对我来说,这看起来比 gensym 更干净,结果明显相同。我确信我遗漏了一个重要的细节,所以我的问题是,它是什么?
GENSYM
就像 MAKE-SYMBOL
。不同之处在于 GENSYM
通过向上计数支持奇特的命名 -> 因此符号具有唯一的名称,这使得在宏扩展中使用 gensyms 时调试更容易一些。
#:foo
是 reader.
的符号
所以你有一个创建这些和文字符号的函数。请注意,当 *print-circle*
为真时,s 表达式中可能会保留某种标识:#(#1=#:FOO #1#)
.
一般这类似于(a . b)
和(cons 'a 'b)
,#(a b)
和(vector 'a 'b)
...一个是文字数据,另一个是将创建的表单('cons') 新鲜 个对象.
如果您查看您的宏,主要问题是它的嵌套使用可能会导致问题。无论是词汇还是动态。
词法上可以是同一个变量,就是rebound
动态的,如果是特殊变量也可以反弹
在宏扩展时使用生成的符号将确保不同的扩展代码不会共享绑定。
每次展开宏时,都会使用相同的符号。
(defmacro foo () `(quote #:x))
(defmacro bar () `(quote ,(gensym)))
(eq (foo) (foo)) => t
(eq (bar) (bar)) => nil
Gensym 每次求值时都会创建一个新符号,但是尖冒号只会在读取时创建一个新符号。
虽然使用尖冒号不太可能导致问题,但在极少数情况下使用它会导致几乎不可能找到错误。最好始终使用 gensym 以确保安全。
如果您想使用尖冒号之类的东西,您应该查看 Let Over Lambda 中的 defmacro! 宏。
我刚刚阅读了 sharpsign 冒号 reader 宏,听起来它与 gensym
的效果非常相似Sharpsign Colon: "introduces an uninterned symbol"
Gensym: "Creates and returns a fresh, uninterned symbol"
这么简单的测试
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {1002FF77D3}>.
CL-USER> (defparameter #:dave 1)
#:DAVE
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {100324B493}>.
很酷,所以失败了。
现在进行宏观测试
(defmacro test (x)
(let ((blah '#:jim))
`(let ((,blah ,x))
(print ,blah))))
CL-USER> (test 10)
10
10
CL-USER>
很好,所以它可以像 gensym 一样使用。
对我来说,这看起来比 gensym 更干净,结果明显相同。我确信我遗漏了一个重要的细节,所以我的问题是,它是什么?
GENSYM
就像 MAKE-SYMBOL
。不同之处在于 GENSYM
通过向上计数支持奇特的命名 -> 因此符号具有唯一的名称,这使得在宏扩展中使用 gensyms 时调试更容易一些。
#:foo
是 reader.
所以你有一个创建这些和文字符号的函数。请注意,当 *print-circle*
为真时,s 表达式中可能会保留某种标识:#(#1=#:FOO #1#)
.
一般这类似于(a . b)
和(cons 'a 'b)
,#(a b)
和(vector 'a 'b)
...一个是文字数据,另一个是将创建的表单('cons') 新鲜 个对象.
如果您查看您的宏,主要问题是它的嵌套使用可能会导致问题。无论是词汇还是动态。
词法上可以是同一个变量,就是rebound
动态的,如果是特殊变量也可以反弹
在宏扩展时使用生成的符号将确保不同的扩展代码不会共享绑定。
每次展开宏时,都会使用相同的符号。
(defmacro foo () `(quote #:x))
(defmacro bar () `(quote ,(gensym)))
(eq (foo) (foo)) => t
(eq (bar) (bar)) => nil
Gensym 每次求值时都会创建一个新符号,但是尖冒号只会在读取时创建一个新符号。
虽然使用尖冒号不太可能导致问题,但在极少数情况下使用它会导致几乎不可能找到错误。最好始终使用 gensym 以确保安全。
如果您想使用尖冒号之类的东西,您应该查看 Let Over Lambda 中的 defmacro! 宏。