clisp正数
我试图使用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
(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)