我们今天刚刚在课堂上讨论了循环,我有一些事情需要做。简单地说,我必须使用循环而不是递归来构建列表。我似乎在这里遇到了绊脚石。对于这个例子,我们需要做一个简单的倒计时。该函数接受一个参数,然后返回小于或等于初始参数的所有正整数的列表。(倒计时5)=>(5 4 3 2 1)
无论出于什么原因,我都很难找到循环。我们谈论的是Loop、Do、Dotimes和Dolist。我试过几个循环,结果总是相似。
(defun countdown (num)
(cond ((= num 0) nil)
(T (let* ((list nil))
(loop
(if (= num 0) (return list)
(setf list (cons list num)))
(setf num (- num 1)))))))
我的输出显示如下:
(((((NIL . 5) . 4) . 3) . 2) .1)
更新:我已经解决了这个问题。显然,我需要颠倒cons
中的顺序,所以num
在list
之前。有人想解释一下吗?我以为你把列表放在第一位,然后你放在第二位的内容会添加到它的末尾。至少,到目前为止,我一直在使用它,没有问题。
将参数反转为cons
(以及原因)
你在回答中写道(既然它要求更多信息,也许应该是一条评论):
我已经解决了这个问题。显然我需要在缺点,所以num在列表之前。有人想解释一下吗?我你以为你把清单放在第一位,然后你放在第二位的是添加到它的末尾。至少,到目前为止我一直是这样使用它的没有问题。
HyperSpec中清楚地记录了该函数:函数CONS。文档中的示例显示,例如
(cons 1 (cons 2 (cons 3 (cons 4 nil)))) => (1 2 3 4)
(cons 'a (cons 'b (cons 'c '()))) => (A B C)
(cons 'a '(b c d)) => (A B C D)
甚至纸币
如果对象2是一个列表,那么cons可以被认为是生成了一个新的列表,这个列表与它相似,但前面已经准备好了对象1。
这可能有助于阅读14.1.2 Conses as Lists,其中包括:
列表是一个conses链,其中每个cons的car是列表的一个元素,每个cons中的cdr要么是链中的下一个链接,要么是终止原子。
关于loop
这里的许多答案都向您指出,循环形式包含一种特殊的迭代语言。这是真的,但它也可以按照你使用它的方式使用。这种方式被称为简单循环:
6.1.1.1.1简单回路
一个简单的循环形式是一个主体只包含化合物的循环形式表格。从左到右依次评估每个表单。当最后一个表单已经被评估,然后第一个表单再次被评估,等等,在一个永无止境的循环中。一个简单的循环形式建立名为nil的隐式块。简单循环的执行可以是通过显式地将控制转移到隐式块而终止(使用return或return from)或到block(例如,使用throw、go或return from)。
简单的循环可能不像使用循环提供的更好功能的循环那样常见,但如果您只是在课堂上介绍了这一点,您可能还没有做到。不过,其他答案确实提供了一些很好的例子。
如果你谈论常见的lisp循环,你的倒计时可能是这样的:
(defun countdown (from-number)
(loop :for x :from from-number :downto 1 :collect x))
CL-USER> (countdown 10)
(10 9 8 7 6 5 4 3 2 1)
使用loop
,它有自己的"特殊用途语言",看起来不像Lisp:
(defun countdown (n)
(loop
for i from n downto 1
collect i))
或使用do
:
(defun countdown (n)
(do ((i 1 (1+ i))
(res nil (cons i res)))
((> i n) res)))
请参阅此处,特别是第7章和第22章。