`intern` 函数的目的是什么?

What is the purpose of the `intern` function?

我正在关注 an article 作者定义了以下宏:

(defmacro make-is-integral-multiple-of (n)
  (let ((function-name (intern (concatenate
                                'string
                                (symbol-name :is-integral-multiple-of- )
                                (write-to-string n)))))
    `(defun ,function-name (x)
       (equal 0 (mod x, n)))))

该宏易于阅读和理解,但我想知道:我们何时以及为何明确需要 intern 函数?

删除它会破坏宏,然后 returns 错误:

The value "IS-INTEGRAL-MULTIPLE-OF-3"
is not of type
  (OR SYMBOL CONS).

这是否意味着每次宏定义新符号时都必须调用 interninterndefmacro 语句之外是否有任何用途?欢迎提供见解。

intern 找到或创建一个 具有包中提供的名称的符号。

这意味着它必须在宏创建符号时使用。 您示例中的宏是一个相当典型的用例,除了人们通常使用 #:is-integral-multiple-of- 之类的非内部符号而不是关键字 :is-integral-multiple-of-.

在其他情况下它可能会有用。 一般来说,一个包就是一个特殊用途的table映射字符串到符号,intern对应(setf gethash).

例如,您可以使用以下方法之一来保留您的数据:

(defvar *operators* (make-hash-table :test 'equal))
(defstruct operator name help function)
(defun make-op (name help function)
  (setf (gethash name *operators*)
        (make-operator :name name
                       :help help
                       :function function)))
(make-op "build-house"
         "construct a house out of the supplied materials"
         (lambda (bricks mortar) ...))
(funcall (operator-function (gethash "build-house" *operators*))
         (list "brick1" "brick2" ...)
         (make-mortar))

(defpackage #:operators)
(defun make-op (name help function)
  (let ((op (intern name #:operators)))
    (setf (symbol-value op) help
          (fdefinition op) function)))
(make-op "build-house"
         "construct a house out of the supplied materials"
         (lambda (bricks mortar) ...))
(funcall #'operators::build-house
         (list "brick1" "brick2" ...)
         (make-mortar))

使用 symbol-name 获取操作员名称,帮助是 symbol-value

函数名称

函数名的类型必须是(OR SYMBOL CONS)。这是 Common Lisp 标准所要求的。

因此名称必须是 symbollist。通常 Lisp 中的函数名必须是符号。它们可以是列表对于 setf 函数 来说是相对特殊的。在 Common Lisp 中,它只能是一个列表,如 (setf foo),以 setf 作为第一个符号。在普通的 Common Lisp 中不允许使用其他列表作为函数名称。 (旁注,较旧的 Lisp Machine Lisp 有其他列表作为函数名称)。

(defun foo (bar)     ; FOO is a symbol and the name of the function
  (+ 42 bar))

以下是不寻常的,实际上是 Common Lisp 的一个特征:

(defun (setf a) (new-value thing)    ; (setf a) is the name of the function
  (setf (first thing) new-value))

使用 INTERN 和 MAKE-SYMBOL 生成函数名

所以,如果你想生成一个新的函数名,它需要是一个符号。首先将新名称生成为字符串,然后从该字符串生成一个符号。

创建符号的方法有多种。 INTERN 将查看符号是否已存在于包中(当前包是默认包)。如果它不存在,它将创建一个新的并在那个包中实习那个符号。

也可以使用 MAKE-SYMBOL 创建符号,但该符号不会在任何包中。这使得通常很难访问该符号。

通常一个函数名应该是一个符号,它被嵌入在一些包中。仅在极少数情况下,例如某些计算代码的情况下,将未实习的符号作为函数名才有用。