在Common中,我有一个合并排序的通用实现:我有不同的拆分和合并函数的实现,对于拆分和合并函数的每一个组合,我想要构造一个合并排序函数。
每个合并排序函数都是通过调用以下函数创建的:
(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,以保持其名称的私有性,并避免破坏名称空间。
我的代码使用几个通用Lisp实现(例如,Steel ):
所以,我假设我的代码是正确的。
但是,如果我使用快板通用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-function和merge-function),那么警告就会消失。
在快板公共Lisp中,我没有找到任何关于这个警告的含义的指示。我尝试过的其他实现(ABCL、CMUCL、CCL、CLISP、SBCL)不会发出任何警告。我认为可以多次定义内部函数(闭包)的新实例,我不明白为什么会出现问题。有什么想法吗?
发布于 2014-04-18 21:06:39
您从不在公共Lisp中嵌套defun。
就像在defun中使用defvar而不是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))发布于 2014-05-01 07:13:14
您没有显示测试代码,因此,请考虑以下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则重新定义了它。
https://stackoverflow.com/questions/23161698
复制相似问题