`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).
这是否意味着每次宏定义新符号时都必须调用intern
? intern
在defmacro
语句之外是否有任何用途?欢迎提供见解。
【问题讨论】:
【参考方案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` 函数的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章