LISP 函数总是返回 nil

LISP function always returning nil

(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 练习,我才开始学习不久。

我正在浏览列表并将元素插入到 'before' 列表中。如果我要插入的数字小于我当前所在的列表元素,我将要插入的数字附加到 'before' 列表中,然后我将原始列表 'lst' 的剩余部分附加到 'before' 列表,然后返回 'before'.

但是,这个函数总是returns NIL。任何想法为什么?我的意思是,pop 和 nconc 都是破坏性的...

在 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)))

让我们看看你的代码的几个问题。

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

如果您在列表中使用 LENGTHNTH,您可以打赌这是错误的。列表是链表,像 LENGTHNTH 这样的操作可能很昂贵。特别是如果在循环或递归调用中完成了无数次。如果你想使用这些函数,那么 vectors 是自然的选择。如果您想使用列表,请尽量避免使用这些功能。链表唯一的 'cheap' 操作是链表头部的操作。

如果,RETURN

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

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

最好写成

... (如果有什么 然后 否则)

循环

for n from 0 to (1- something)

只是

for n below something

NCONC

始终使用 NCONC 的 return 值。 return 值是串联列表。

内置功能

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)