我跟随作者定义以下宏的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
的使用?欢迎见解。
答案 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
创建符号,但该符号不会出现在任何包中。这使得访问该符号通常很困难。
通常,函数名称应该是符号,在某个包中实例化。只有在极少数情况下,例如计算代码的某些情况,将未处理的符号作为函数名称才有用。