clisp正数

clisp正数,lisp,common-lisp,Lisp,Common Lisp,我试图使用clisp从函数参数列表返回一个包含非负数的列表 (defun recursive (L) (setq ret (list)) (setq first (car L)) (setq rest (cdr L)) (if (null L) 0 (if (>= first 0) (nconc ret (first)) (recursive rest)))) (se

我试图使用clisp从函数参数列表返回一个包含非负数的列表

(defun recursive (L)
    (setq ret (list)) 
    (setq first (car L))
    (setq rest (cdr L))
    (if (null L) 
        0 
        (if (>= first 0) 
            (nconc ret (first)) 
            (recursive rest))))

(setq mylist (list 1 2 3 -1 0 -3))
(write (recursive mylist))
我写了这篇文章,希望输出为
(1230)


该代码有什么问题?

首先,您的代码不起作用,因为您在
if
的then分支中将
First
用作函数(
(First)

除此之外,每次调用
recursive
,都会将
ret
重新初始化为空列表。而在
if
中,只有当数字不大于0时,才会递归

下面是一个使用
cond
的有效解决方案:

(defun filter-non-negative (l)
   (cond
    ((null l)                   ;; empty list
     nil)
    ((>= (first l) 0)      ;; number >= 0
     (cons (first l) (filter-non-negative (rest l))))
    (t                         ;; all other cases 
     (filter-non-negative (rest l)))))

(write (filter-non-negative '(1 2 3 -1 0 -3)))
;; (1 2 3 0)

首先,您的代码不起作用,因为您在
if
的then分支中将
First
用作函数(
(First)

除此之外,每次调用
recursive
,都会将
ret
重新初始化为空列表。而在
if
中,只有当数字不大于0时,才会递归

下面是一个使用
cond
的有效解决方案:

(defun filter-non-negative (l)
   (cond
    ((null l)                   ;; empty list
     nil)
    ((>= (first l) 0)      ;; number >= 0
     (cons (first l) (filter-non-negative (rest l))))
    (t                         ;; all other cases 
     (filter-non-negative (rest l)))))

(write (filter-non-negative '(1 2 3 -1 0 -3)))
;; (1 2 3 0)

首先,变量
ret
First
rest
应使用
let
在本地定义。在您的版本中,它们是全局变量。请注意,您根本不需要这些变量,只需直接使用函数调用即可。 在上一行之前,您有
(first)
,这将发出错误信号,因为此函数需要一个参数。但是,您需要的不是函数
first
,而是变量
first
,因此您需要
(首先列出)
。 当列表为空时,返回0。由于每次递归调用结束时都会到达这一点,因此这将向任何输入参数添加0。您应该返回nil。 最后,不要使用
ncoc
查看函数
cons

顺便说一句,请注意有一个函数
remove if
,它将完全完成您想要的工作,但我知道您正在尝试学习递归调用。
我希望这会有所帮助。

首先,变量
ret
First
rest
应该使用
let
在本地定义。在您的版本中,它们是全局变量。请注意,您根本不需要这些变量,只需直接使用函数调用即可。 在上一行之前,您有
(first)
,这将发出错误信号,因为此函数需要一个参数。但是,您需要的不是函数
first
,而是变量
first
,因此您需要
(首先列出)
。 当列表为空时,返回0。由于每次递归调用结束时都会到达这一点,因此这将向任何输入参数添加0。您应该返回nil。 最后,不要使用
ncoc
查看函数
cons

顺便说一句,请注意有一个函数
remove if
,它将完全完成您想要的工作,但我知道您正在尝试学习递归调用。
我希望这有帮助。

过滤器成为您想要实现的功能。
然后
(filter nil)
应返回nil。 在一般情况下,您可以递归地编译
(filter(number.tail))
。假设
filter
计算列表中的正数列表,您可以解决
tail
的问题,并调用
(filter tail)
。为了解决当前的问题,你必须考虑<代码>号码<代码>是否正确,并相应地将元素添加到递归结果。
(defun filter (list)
  (etypecase list
    (null nil)
    (cons (destructuring-bind (number . tail) list
            (if (plusp number)
                (cons number (filter tail))
                (filter tail))))))
我用的是,,但是你可以用不同的方式来表达。请注意,您使用了需要在整个列表上迭代的方法,这不是必需的,并且使整个aproach在时间上是二次的

上述函数有一个缺陷,因为调用堆栈的大小随输入列表的大小线性增长。每次调用filter时,都会在堆栈上分配一个新帧,可以通过以下方式轻松查看:

之所以会出现这种情况,是因为您需要记住递归调用中
number
的每个中间值,以便
cons
使用递归结果处理它们。如果您可以在进入递归调用之前完成所有工作,那么就不需要保留中间值,并且函数将是递归终端,并且可以进行所谓的尾部调用优化。 为此,您必须在调用递归调用之前通过累加器构建结果列表:

(defun filter (list accumulator)
  (etypecase list
    (null accumulator)
    (cons (destructuring-bind (head . tail) list
            (if (plusp head)
                (filter tail (cons head accumulator))
                (filter tail accumulator))))))
注意重复,可以重构为:

(filter tail (if (plusp head) (cons head accumulator) accumulator))
在上面,我们添加了一个保存新列表的
累加器
。最初,您应该传递一个空列表。当到达输入列表的末尾时,返回累加器。否则,在递归调用
filter
之前,将该号码添加到累加器中。区别在于不需要在调用堆栈中存储中间值。跟踪宏会产生以下结果:

0: (FILTER (0 1 -2 3 -4 -5 6 7 -8 9) NIL)
  1: (FILTER (1 -2 3 -4 -5 6 7 -8 9) NIL)
    2: (FILTER (-2 3 -4 -5 6 7 -8 9) (1))
      3: (FILTER (3 -4 -5 6 7 -8 9) (1))
        4: (FILTER (-4 -5 6 7 -8 9) (3 1))
          5: (FILTER (-5 6 7 -8 9) (3 1))
            6: (FILTER (6 7 -8 9) (3 1))
              7: (FILTER (7 -8 9) (6 3 1))
                8: (FILTER (-8 9) (7 6 3 1))
                  9: (FILTER (9) (7 6 3 1))
                    10: (FILTER NIL (9 7 6 3 1))
                    10: FILTER returned (9 7 6 3 1)
                  9: FILTER returned (9 7 6 3 1)
                8: FILTER returned (9 7 6 3 1)
              7: FILTER returned (9 7 6 3 1)
            6: FILTER returned (9 7 6 3 1)
          5: FILTER returned (9 7 6 3 1)
        4: FILTER returned (9 7 6 3 1)
      3: FILTER returned (9 7 6 3 1)
    2: FILTER returned (9 7 6 3 1)
  1: FILTER returned (9 7 6 3 1)
0: FILTER returned (9 7 6 3 1)
请注意,该函数是尾部递归函数,但由于存在箭头形状的跟踪,它看起来不像是经过了优化。然而,跟踪并不是一种可靠的方法来知道函数是否是尾部递归的,因为跟踪的行为改变了实际完成的操作。或者,可能是
调试
质量太高,以至于没有应用尾部调用优化。这取决于您的实现。请注意,跟踪清楚地显示了中间列表是如何构建的,以及结果是如何从深层传递到更高层的。还可以看到列表是反向构建的,因为我们一直使用累加器调用
cons
(这是有效的,与ncoc相反)。 由于您没有指定是否希望列表中的元素保持与输入列表相同的顺序,因此我假设这不是必需的(defun filter (list) (labels ((filter (list accumulator) (etypecase list (null accumulator) (cons (destructuring-bind (head . tail) list (filter tail (if (plusp head) (cons head accumulator) accumulator))))))) (nreverse (filter list nil))))
(defun filter (list)
  (loop for number in list
        when (plusp number)
          collect number))
CL-USER 24 > (remove-if-not #'plusp (list 1 2 3 -1 0 -3))
(1 2 3)
CL-USER 25 > (remove-if (complement #'plusp) (list 1 2 3 -1 0 -3))
(1 2 3)