`intern`功能的目的是什么?

时间:2016-10-02 16:00:29

标签: macros common-lisp symbols

我跟随作者定义以下宏的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函数?

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

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

这是否意味着每次宏应该定义一个新符号时都必须调用intern?在intern声明之外是否有defmacro的使用?欢迎见解。

2 个答案:

答案 0 :(得分:4)

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))

(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

答案 1 :(得分:3)

功能名称

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

因此,名称必须是符号或列表。通常,Lisp中的函数名必须是符号。对于 setf函数,它们可以是列表是相对特殊的。在Common Lisp中,它只能是(setf foo)之类的列表,setf作为第一个符号。普通Lisp中不允许使用其他列表作为函数名。

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

因此,如果要生成新的函数名称,则需要将其作为符号。首先将新名称生成为字符串,然后从该字符串生成符号。

有几种方法可以创建符号。 INTERN将查看包中是否已存在符号(当前包是默认包)。如果它不存在,它将在该包中创建一个新符号和实体符号。

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

通常,函数名称应该是符号,在某个包中实例化。只有在极少数情况下,例如计算代码的某些情况,将未处理的符号作为函数名称才有用。