嵌套的`defun`在Allegro Common Lisp中产生重复警告

时间:2014-04-18 20:22:13

标签: common-lisp allegro-cl

我在Common Lisp中有一个泛型实现的合并排序:我有不同的拆分和合并函数实现,并且对于拆分和合并函数的每个组合,我想构建一个合并排序函数。

  • 任何split函数都会将字符串列表作为输入,并返回两个列表的列表:原始列表的两半。
  • 任何合并函数都会将两个排序列表作为输入,并返回已排序的合并列表。

通过调用以下函数创建每个合并排序函数:

(defun make-merge-sort-function (split-function merge-function)

  (defun merge-sort (lst)
    (if (or (null lst) (null (cdr lst)))
        lst
        (let ((s (funcall split-function lst)))
          (funcall merge-function (merge-sort (car s)) (merge-sort (cadr s))))))

  (lambda (lst)
    (merge-sort lst)))

我在merge-sort中定义了make-merge-sort-function,以便将其名称保密,避免破坏名称空间。

我的代码适用于几个Common Lisp实现(例如Steel Bank Common Lisp):

  • 我的所有测试运行的输出都已正确排序,
  • 每个生成的合并排序函数具有不同的执行时间,表示使用了不同的拆分/合并组合。

所以,我认为我的代码是正确的。

但是,如果我使用Allegro Common Lisp运行该程序,我会收到警告:

Warning: MERGE-SORT is defined more than once as `operator' in file foo.lisp.

其中foo.lisp是调用make-merge-sort-function的文件。因此,程序运行正常,但是在第一个调用后make-merge-sort-function每次调用时都会打印一次此警告。 如果我将merge-sort函数设为全局(另外两个参数split-functionmerge-function),那么警告就会消失。

我在Allegro Common Lisp中没有发现任何有关此警告含义的迹象。我尝试的其他实现(ABCL,CMUCL,CCL,CLISP,SBCL)不会发出任何警告。我认为内部函数(闭包)的新实例被多次定义是可以的,我不明白为什么这应该是一个问题。 有什么想法吗?

2 个答案:

答案 0 :(得分:4)

永远在Common Lisp中嵌套defun

就像你在里面使用let一样 defun代替 你使用defvar 而是labels 嵌套defun

(defun make-merge-sort-function (split-function merge-function)
  (labels ((merge-sort (lst)
             (if (or (null lst) (null (cdr lst)))
                 lst
                 (let ((s (funcall split-function lst)))
                   (funcall merge-function (merge-sort (car s)) 
                                           (merge-sort (cadr s)))))))
    #'merge-sort))

答案 1 :(得分:1)

您没有显示测试代码,因此,请考虑此CLISP会话记录:

[3]> (defun make-merge-sort-function (split-function merge-function)
  (defun merge-sort (lst)
    (if (or (null lst) (null (cdr lst)))
        lst
        (let ((s (funcall split-function lst)))
          (funcall merge-function (merge-sort (car s))
                                  (merge-sort (cadr s))))))
  (lambda (lst)
    (merge-sort lst)))
MAKE-MERGE-SORT-FUNCTION
[4]> (fboundp 'merge-sort)
NIL                         <<---------------------------- NB
[5]> (defun sp1(x)(princ" IN SPL1 ") x)
SP1
[6]> (defun sp2(x)(princ" IN SPL2 ") x)
SP2
[7]> (defun mg1(x y)(princ" IN MRG1 ") x)
MG1
[9]> (setq f1 (make-merge-sort-function #'sp1 #'mg1))
#<FUNCTION :LAMBDA (LST) (MERGE-SORT LST)>
[10]> (fboundp 'merge-sort)
T                           <<---------------------------- NB !!
[12]> (funcall f1 '(1 2 3))
 IN SPL1                    <<---------------------------- NB
*** - CDR: 1 is not a list
[14]> (setq f2 (make-merge-sort-function #'sp2 #'mg1))
#<FUNCTION :LAMBDA (LST) (MERGE-SORT LST)>
[15]> (funcall f1 '(1 2 3))
 IN SPL2                    <<---------------------------- NB !!!
*** - CDR: 1 is not a list

现在你可以看到你的代码正在做一些与你想象的不同的事情,你的测试代码可能只是没有把这个问题搞清楚。

显然,嵌套的defun定义了一个全局可访问的函数merge-sort,第二次调用make-merge-sort-function重新定义了它。