`intern` 函数的目的是啥?

Posted

技术标签:

【中文标题】`intern` 函数的目的是啥?【英文标题】:What is the purpose of the `intern` function?`intern` 函数的目的是什么? 【发布时间】:2017-02-10 15:30:30 【问题描述】:

我正在关注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).

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

【问题讨论】:

【参考方案1】:

函数名称

函数的名称必须是(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))

以下是不寻常的,实际上是 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 创建符号,但该符号不会在任何包中。这使得访问该符号通常很困难。

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

【讨论】:

【参考方案2】:

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

【讨论】:

以上是关于`intern` 函数的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在C#中internal关键字是啥意思?

我的 C# Private Class 可以在 DLL 内的任何地方访问,那么 internal 的用途是啥?

500 internal server error是啥原因

Internal Server Error.是啥意思

在C#中internal关键字是啥意思?

http500internal server error是啥意思?