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每次宏应该定义新符号时都必须调用它?intern在defmacro语句之外有任何用途吗?欢迎提供见解。
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.
函数名
函数的名称需要是 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用来创建符号,但该符号不会在任何包中。这使得通常难以访问该符号。
通常一个函数名应该是一个符号,它被存放在某个包中。仅在极少数情况下,例如某些计算代码的情况,将非内部符号用作函数名称会很有用。