Common Lisp中的未内部化符号

13

我多次听到过非内部符号(uninterned symbols)的概念,但我并不完全清楚它们是什么。

(make-symbol)创建的符号有没有办法被内部化(intern)?
能否在不将符号内部化的情况下为其赋值?
是否可以重命名符号(已内部化或未内部化)?
除了创建之外,还有什么可以用非内部符号来做?

更新:
在这段代码中,符号发生了什么?

CL-USER> (defun func ()
           (let ((var 'sym))
             (print (find-symbol "sym"))
             (print var)))
FUNC
CL-USER> (func)

NIL 
SYM 
SYM

我的错误理解是:
1. find-symbol 输出了 nil,因此该符号未被 interned
2. var 在开头没有 # 号的情况下打印 sym,这意味着它已被 interned


3
符号名称默认大写。使用 FIND-SYMBOL 查找符号时区分大小写。 - Rainer Joswig
我明白了,谢谢。 - sabof
2个回答

13

未经加工的符号主要用作名称或标识符,以避免包中出现混乱或用于相关任务。

例如:

T1> (find-symbol "T2")
NIL
NIL
T1> (find-symbol "T3")
NIL
NIL
T1> (defpackage t2)
#<Package "T2">
T1> (defpackage #:t3)
#<Package "T3">    
T1> (find-symbol "T2")
T2
:INTERNAL
T1> (find-symbol "T3")
NIL
NIL

正如您所看到的,在第一个defpackage表单中使用t2会将其放置在t1包中,而在第二个defpackage中使用#:t3则避免了这种情况。这是可能的,因为defpackage接受一个字符串设计者作为其第一个元素,而符号不需要被interned以作为设计者。
这些和相关情况是非interned符号主要有意使用的地方。您也可以通过使用字符串或关键字来避免污染包,但在第一种情况下,可能会出现人们使用与默认readtable-case不同的问题,而在第二种情况下,您将污染关键字包,这对于一些人来说很重要。(对于这是否真的是一个坏事有不同的意见。)
然后,还有一些情况下,符号失去了它的home-package(例如通过unintern),并且至少变得明显地未interned。(它可能仍然被interned在另一个包中。)
T1> (defparameter *t2* (find-symbol "T2"))
*T2*
T1> (import *t2* "T3")
T
T1> (symbol-package *t2*)
#<Package "T1">
T1> (unintern *t2*)
T
T1> (find-symbol "T2")
NIL
NIL
T1> (symbol-package *t2*)
NIL
T1> *t2*
#:T2
T1> (find-symbol "T2" "T3")
#:T2
:INTERNAL
T1> (unintern *t2* "T3")
T
T1> (import *t2* "T3")
T
T1> *t2*
T3::T2
T1> (symbol-package *t2*)
#<Package "T3">

因此,对于“是否有一种方法可以使使用(make-symbol)创建的符号变为内部符号?”这个问题的答案是肯定的:

T1> (import (make-symbol "T4"))
T
T1> (find-symbol "T4")
T4
:INTERNAL

我可以为一个符号分配一个值而不将其intern吗?

是的,虽然您会失去它可以通过名称和包唯一标识的属性,但您仍然可以使用其值槽、plist等:

T1> (let ((symbol '#:t5))
      (setf (symbol-value symbol) 1)
      (setf (get symbol :foo) :bar)
      (setf (symbol-function symbol) (lambda ()))
      (values (symbol-value symbol)
              (get symbol :foo)
              (symbol-function symbol)))
1
:BAR
#<Anonymous Function #xC829036>

是否可以重命名一个符号(interned或uninterned)?

修改符号名称的后果是不确定的。

未interned符号还能做什么?

我真的认为它们在包定义中主要用作指示器,但一般的答案是:它们可以在您想要命名事物而不使用硬编码字符串和不想污染任何包的情况下非常有用。


还有一个问题,是否可以在语法上以同样的方式intern/unintern一个符号? - sabof
我不理解这个问题,请你能否给出一个例子或更详细的解释? - danlei
Rainer应该在他的评论中澄清这一点。 - danlei

2
  1. Yes

    CL-USER> (intern (string (make-symbol "TEST")))
    TEST
    :INTERNAL 
    
  2. No

  3. No

  4. It is usually used in package declaration not to pollute the namespace of the package, in which the declaration takes place (if an ordinary symbol was used) or keyword package, because entries in defpackage form's :export and :use clauses are converted to string anyway. So, you can use it in functions, which accept anything and convert it to strings. More generally, uninterned symbols can be used as unique objects with a name and nothing else. But usually keyword symbols are used for such purpose.


2
我理解第4点。 但严格来说,在第1点中,你并没有将符号放入池中,而是创建了一个具有相同名称的不同符号。 - sabof

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接