Lisp 如何定义创建函数别名的函数?
Lisp论坛线程有一个使用如下表单创建函数别名的示例Lisp 如何定义创建函数别名的函数?,lisp,common-lisp,sbcl,Lisp,Common Lisp,Sbcl,Lisp论坛线程有一个使用如下表单创建函数别名的示例 (setf (symbol-function 'zero?) #'zerop) 这很好,使zero?成为有效的谓词。是否可以在不使用宏的情况下参数化此表单?我希望能够调用以下函数并让它创建函数?: (define-predicate-alias 'functionp)` 我的看法大致如下: (defun defalias (old new) (setf (symbol-function (make-symbol new))
(setf (symbol-function 'zero?) #'zerop)
这很好,使zero?
成为有效的谓词。是否可以在不使用宏的情况下参数化此表单?我希望能够调用以下函数并让它创建函数?
:
(define-predicate-alias 'functionp)`
我的看法大致如下:
(defun defalias (old new)
(setf (symbol-function (make-symbol new))
(symbol-function old)))
(defun define-predicate-alias (predicate-function-name)
(let ((alias (format nil "~A?" (string-right-trim "-pP" predicate-function-name))))
(defalias predicate-function-name alias)))
(define-predicate-alias 'zerop)
(zero? '())
尝试调用zero?
时失败
函数COMMON-LISP-USER::ZERO?
未定义
生成符号
创建不需要的符号。这就是为什么zero?
是未定义的
将您的
(新建符号)
替换为例如(intern new*package*)
。(或者您可能需要更仔细地考虑在哪个包中插入新符号。)使符号创建一个不需要的符号。这就是为什么zero?
是未定义的
将您的(新建符号)
替换为例如(intern new*package*)
。(或者您可能想更仔细地考虑在哪个包中插入新符号。)您的代码通过MAKE-symbol
生成符号,但您不会将其放入包中
使用函数INTERN
将符号添加到包中
要扩展Lars的答案,请选择正确的软件包。在这种情况下,默认情况可能是使用别名函数中的相同包:
关于风格:
任何以DEF
开头的内容实际上都应该是宏。如果有函数,请不要使用以“DEF”开头的名称。如果你看一下公共Lisp语言,所有这些都是宏。例如:对于那些定义表单的人,人们通常认为它们在编译文件时会产生副作用:编译器会得到关于它们的信息。函数不能
如果我把这样的东西放进文件里
(define-predicate-alias zerop)
(zero? '())
然后编译该文件,我希望不会看到任何关于未定义的ZERO?
的警告。因此,宏需要将(定义谓词别名'zerop)
扩展为某种东西,使新的ZERO?
在编译时环境中为人所知
我也会将新名称作为第一个参数
因此,对函数使用类似于MAKE-PREDICATE-ALIAS
的内容,而不是DEFINE-PREDICATE-ALIAS
。您的代码通过MAKE-symbol
生成符号,但您不将其放入包中
使用函数INTERN
将符号添加到包中
要扩展Lars的答案,请选择正确的软件包。在这种情况下,默认情况可能是使用别名函数中的相同包:
关于风格:
任何以DEF
开头的内容实际上都应该是宏。如果有函数,请不要使用以“DEF”开头的名称。如果你看一下公共Lisp语言,所有这些都是宏。例如:对于那些定义表单的人,人们通常认为它们在编译文件时会产生副作用:编译器会得到关于它们的信息。函数不能
如果我把这样的东西放进文件里
(define-predicate-alias zerop)
(zero? '())
然后编译该文件,我希望不会看到任何关于未定义的ZERO?
的警告。因此,宏需要将(定义谓词别名'zerop)
扩展为某种东西,使新的ZERO?
在编译时环境中为人所知
我也会将新名称作为第一个参数
因此,在函数中使用类似于MAKE-PREDICATE-ALIAS
的内容,而不是DEFINE-PREDICATE-ALIAS
。已经有一些答案解释了如何做到这一点,但我要指出:
命名约定,P
和-P
Common Lisp有一种命名约定,这种约定大部分都是遵循的(即使在标准库中也有例外),即如果类型名是多个单词(包含-
),那么它的谓词将使用-p
后缀命名,而如果它没有,后缀就是p
。所以我们有keyboard p
和lcd-monitor-p
。这样很好,您使用的是(string right trim“-pP”predicate function name))
,但是由于标准中的…P
和…P
名称,以及由defstruct
生成的名称将使用P
,而不是P
,因此您可以只使用(string right trim)-P“谓词函数名))
。当然,即使这样,一些名字(例如,pop
)也可能有问题,但我想这只是地域的问题
符号名称、格式
和*打印案例*
更重要的是,使用format
为后续实习创建符号名是危险的,因为format
并不总是用字符打印符号名,而字符实际出现在符号名中。例如:
(let ((*print-case* :downcase))
(list (intern (symbol-name 'foo))
(intern (format nil "~A" 'foo))))
;=> (FOO |foo|) ; first symbol has name "FOO", second has name "foo"
使用字符串连接和直接提取符号名可能会更好。这意味着您可以编写这样的代码(这是一个稍微不同的用例,因为其他问题已经解释了如何做您正在尝试做的事情):
已经有一些答案解释了如何做到这一点,但我要指出:
命名约定,P
和-P
Common Lisp有一种命名约定,这种约定大部分都是遵循的(即使在标准库中也有例外),即如果类型名是多个单词(包含-
),那么它的谓词将使用-p
后缀命名,而如果它没有,后缀就是p
。所以我们有keyboard p
和lcd-monitor-p
。这样很好,您使用的是(string right trim“-pP”predicate function name))
,但由于标准中的..P
和..-P
名称,以及由defstruct
生成的名称将使用P
,而不是
(macroexpand-1 '(defpredicate zero))
;=> (DEFUN ZEROP (X) (TYPEP X 'ZERO))
(macroexpand-1 '(defpredicate lcd-monitor))
;=> (DEFUN LCD-MONITOR-P (X) (TYPEP X 'LCD-MONITOR))