为什么要替换"(null x)"用"(null(cdr x))"使这段代码有效吗?

时间:2014-04-15 06:02:22

标签: lisp common-lisp

我是LISP的新手。我试图在LISP中编写冒泡排序功能。

这是我迄今为止所做的。

(defun mysort (x)
  (if (null  x) x
    (if (< (car x) (cadr x))
     (cons (car x) (mysort (cdr l)))
     (cons (cadr x) (mysort (cons (car x) (cddr x)))))))

我收到错误

NIL is not a real number

当我修改代码时(在引用几个代码之后) -

(defun mysort (x)
  (if (null  (cdr x)) x
   (if (< (car x) (cadr x))
    (cons (car x) (mysort (cdr l)))
    (cons (cadr x) (mysort (cons (car x) (cddr x)))))))

现在工作正常。

为什么要更换     (if(null x)x ...) 同     (if(null(cdr x))x ...) 有所作为?

另外,我从另一个函数调用mysort来运行它(长度x)次数。是否可以在单个递归循环中实现完全排序,只使用基本函数?

2 个答案:

答案 0 :(得分:4)

如果你想看第一个元素是否小于第二个元素,那么列表需要至少有两个元素。

如果只有一个元素,CADR会返回NIL。这不是一个数字。

CL-USER 18 > (cadr '(1))
NIL

您的Lisp系统不仅应该告诉您错误,还应该告诉您发生错误的函数。这里:函数<

使用(null (cdr list))是测试是否存在第二个元素的好方法。典型的错误是调用LENGTH,效率很低。

答案 1 :(得分:1)

要进行比较,您至少需要两个元素,因此检查x是否NIL是不够的。

检查(cdr x)是否为NIL是检查列表长度是否至少为2的好方法,因为NIL是特殊的,即使它不是一个缺点单元格它保证(cdr NIL)NIL

您收到的错误是因为NIL不是数字,因此您无法与<数字进行比较,而(< (car x) (cadr x))执行x时会发生这种情况是一个包含单个元素的列表。

关于在单个递归调用中进行排序,您可以使用此排序定义:

  • 排序空列表
  • 如果第一个元素是列表的最小值并且列表的其余部分已排序,则对非空列表进行排序。

这导致

(defun mysort (x)
  (if x
      (let ((minimum (reduce #'min x)))
        (cons minimum
              (mysort (remove minimum x :count 1))))))

顺便说一下,这是一种非常低效的排序方式。