如何定义创建函数别名的函数?

时间:2013-11-25 08:31:43

标签: lisp common-lisp sbcl

Lisp论坛帖子Define macro alias?有一个使用诸如

之类的表单创建函数别名的示例
(setf (symbol-function 'zero?) #'zerop)

这很好用,使zero?成为有效的谓词。是否可以在不使用宏的情况下参数化此表单?我希望能够调用以下内容并创建function?

(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?未定义。

3 个答案:

答案 0 :(得分:2)

make-symbol创建一个未加工的符号。这就是zero?未定义的原因。

将您的(make-symbol new)替换为例如(intern new *package*)。 (或者您可能想要更仔细地考虑在哪个包中实习您的新符号。)

答案 1 :(得分:1)

您的代码通过MAKE-SYMBOL创建了一个符号,但您没有将其放入包中。

使用函数INTERN将符号添加到包中。

要扩展Lars的答案,请选择正确的包裹。在这种情况下,默认可能是使用别名函数中的相同包:

关于风格:

DEF开头的任何内容都应该是一个宏。如果您有一个功能,请不要使用以“DEF”开头的名称。如果你看一下Common Lisp语言,所有这些都是宏。例如:对于那些定义表单,人们通常会期望它们在编译文件时有副作用:编译器会获得有关它们的信息。功能不能。

如果我把这样的东西放在一个文件中

(define-predicate-alias zerop)

(zero? '())

然后编译该文件,我希望看不到有关未定义ZERO?的任何警告。因此,宏需要将(define-predicate-alias 'zerop)扩展为使新ZERO?在编译时环境中已知的内容。

我也会把新名称作为第一个参数。

因此,为函数使用MAKE-PREDICATE-ALIAS而不是DEFINE-PREDICATE-ALIAS之类的东西。

答案 2 :(得分:1)

已经有一些答案可以解释你如何做到这一点,但我要指出:

命名约定,P-P

Common Lisp有一个主要遵循的命名约定(即使在标准库中也有例外),如果类型名称是多个单词(包含-),则其谓词以-P后缀,如果不是,则后缀仅为P。所以我们有keyboardplcd-monitor-p。那么,您使用(string-right-trim "-pP" predicate-function-name))就好了,但由于标准中的…P…-P名称以及defstruct生成的名称将会使用P,而不是p,您可能只使用(string-right-trim "-P" predicate-function-name))。当然,即使这有一些名称可能存在问题(例如pop),但我想这只是领土。

符号名称,format*print-case*

更重要的是,使用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"

最好使用字符串连接并直接提取符号名称。这意味着您可以编写类似的代码(这是一个稍微不同的用例,因为其他问题已经解释了您如何做您正在尝试做的事情):

(defmacro defpredicate (symbol)
  (flet ((predicate-name (symbol)
           (let* ((name (symbol-name symbol))
                  (suffix (if (find #\- name) "-P" "P")))
             (intern (concatenate 'string name suffix)))))
    `(defun ,(predicate-name symbol) (x)
       (typep x ',symbol)))) ; however you're checking the type
(macroexpand-1 '(defpredicate zero))
;=> (DEFUN ZEROP (X) (TYPEP X 'ZERO))

(macroexpand-1 '(defpredicate lcd-monitor))
;=> (DEFUN LCD-MONITOR-P (X) (TYPEP X 'LCD-MONITOR))