我的教授给了我们一个关于clisp的复习任务。一个练习是以三种方式实现相同的目的:返回给定列表中所有正整数的扁平列表。
现在,只有一种方式我真的喜欢这样做,使用cons和递归,但他希望我使用mapcan和循环来做这件事(我怀疑lisp不是他的首选语言因为这种编码风格对lisp的性质非常有抵抗力。我很难弄清楚如何使用循环来完成这个...我想首先要开始一个列表吗?
我为模糊的语言道歉,因为我不确定如何使用函数式语言来编写程序。以下是我的第一次尝试。
(defun posint-loop (l)
(loop for i in l
do (if (listp i)
(posint-loop i)
(if (integerp i)
(if (> i 0)
(append i) ; this doesn't work because there's nothing to
; start appending to!
nil)
nil))))
答案 0 :(得分:2)
要建立新的词法绑定,请使用let
或with
的loop
关键字。为了扩展现有列表,您可能希望使用push
;如果您需要原始订单,可以nreverse
新列表finally
。
另一种方法是使用when
的collect
和loop
个关键字。
另一个提示:mapcan
隐式创建一个新列表。
答案 1 :(得分:1)
Mapcan将一个函数应用于列表的每个元素,期望函数返回一个列表,然后将这些结果列表连接在一起。要将其应用于此问题,您只需处理顶级列表的每个元素。如果元素是列表,则需要递归处理它。如果不是,那么您需要返回一个空列表(不会在最终结果中添加任何元素)或仅包含该元素的列表(这将仅添加该元素到最终结果):
(defun flatten2 (list)
(mapcan (lambda (x)
(cond
((listp x) (flatten2 x))
((and (integerp x) (plusp x)) (list x))
(t '())))
list))
(flatten2 '((a 1 -4) (3 5 c) 42 0))
;=> (1 3 5 42)
使用循环,你可以做同样的事情,认识到(mapcan f list)在功能上等同于(列表nconc中的x循环(funcall fx))< / strong>即可。考虑到这一点,我们有:
(defun flatten3 (list)
(loop for x in list
nconc (cond
((listp x) (flatten3 x))
((and (integerp x) (plusp x)) (list x))
(t '()))))