LISP函数总是返回nil

时间:2015-11-26 13:47:47

标签: list merge insert lisp common-lisp

(defun insert (number lst)
    (let ((before nil))
        (if (= (length lst) 0) (return-from insert (list number)))
        (loop for n from 0 to (1- (length lst)) do
            (if (< number (nth n lst)) (progn (nconc before (list number)) (nconc before lst) (return-from insert before) ) 
             (progn (nconc before (list (pop lst))))))
        (nconc before (list number))
        (return-from insert before)))

所以,我正在尝试插入一个在列表中排序的数字。原谅我的LISP练习不好,我不久前开始学习。

我将浏览列表并将元素插入“之前”列表中。如果我要插入的数字小于我当前所在的列表元素,我将数字附加到'之前'列表中,然后我将原始列表'lst'的左边附加到'之前'列表中,然后返回'之前'。

但是,此函数始终返回NIL。有什么想法吗?我的意思是,pop和nconc都具有破坏性......

2 个答案:

答案 0 :(得分:4)

在Common Lisp中,在修改列表的意义上,在列表中插入值不是一个好习惯。相反,通常的做法是编写一个函数,给定一个列表,构建一个 new 列表,并在正确的位置插入元素。

例如,如果要在已排序的列表中插入数字,可以使用简单的递归函数来执行此操作:

(defun insert (number lst)
  (cond ((null lst) (list number))
        ((<= number (car lst)) (cons number lst))
        (t (cons (car lst) (insert number (cdr lst))))))

(insert 3 '(1 2 5 9))
(1 2 3 5 9)

在您的函数中,您使用nconc,因为它不仅应修改列表,还应修改包含它的变量。但如果变量是空列表,则不会发生这种情况。例如:

> (setq a nil)
NIL
> (nconc a (list 4 5))
(4 5)
> a
NIL

您应始终将nconc的结果分配给您要修改的变量,例如(setq a (nconc a (list 4 5)))

答案 1 :(得分:4)

让我们看一下代码中的一些问题。

效率低下:错误的数据结构或错误的操作选择

如果您在列表中使用LENGTHNTH,则可以打赌这是错误的。列表是链接列表,LENGTHNTH等操作可能很昂贵。特别是如果在循环或递归调用中完成了无数次。如果您想使用这些功能,那么向量是自然的选择。如果要使用列表,请尽量避免使用这些功能。链表的唯一“便宜”操作是列表的首位。

IF,RETURN

如果您需要RETURNRETURN-FROM,那么您有可能不使用Lisp的内置数据流。

...
(if something (return ...))
...)

更好地写为

... (如果有的话   然后   别的)

<强> LOOP

for n from 0 to (1- something)

只是

for n below something

<强> NCONC

始终使用NCONC的返回值。返回值是连接列表。

内置功能

CL-USER 12 > (defun insert (number list)
               (merge 'list list (list number) #'<))
INSERT

CL-USER 13 > (insert 10 (list 1 2 3 7 8 10 40))
(1 2 3 7 8 10 10 40)