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

dan*_*gom 4 macros symbols common-lisp

我在下面的文章在这里笔者定义了以下宏:

(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)))))
Run Code Online (Sandbox Code Playgroud)

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

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

The value "IS-INTEGRAL-MULTIPLE-OF-3"
is not of type
  (OR SYMBOL CONS).
Run Code Online (Sandbox Code Playgroud)

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

sds*_*sds 6

intern 在包中查找或创建具有提供名称的符号。

这意味着它具有当宏创建一个符号使用。您示例中的宏是一个相当典型的用例,除了人们通常使用诸如#:is-integral-multiple-of-而不是关键字之类的非实习符号:is-integral-multiple-of-

在其他情况下它可能有用。一般来说,包是将字符串映射到符号的特殊用途表,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))
Run Code Online (Sandbox Code Playgroud)

或者

(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))
Run Code Online (Sandbox Code Playgroud)

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


Rai*_*wig 5

函数名

函数的名称需要是 type (OR SYMBOL CONS)。这是 Common Lisp 标准所要求的。

因此,名称必须是符号列表。通常 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))
Run Code Online (Sandbox Code Playgroud)

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

(defun (setf a) (new-value thing)    ; (setf a) is the name of the function
  (setf (first thing) new-value))
Run Code Online (Sandbox Code Playgroud)

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

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

有多种方法可以创建符号。INTERN将查看符号是否已存在于包中(当前包是默认值)。如果它不存在,它将创建一个新符号并将该符号驻留在该包中。

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

通常一个函数名应该是一个符号,它被存放在某个包中。仅在极少数情况下,例如某些计算代码的情况,将非内部符号用作函数名称会很有用。