Common Lisp 中几种常见循环语句(dolist dotimes do)返回值和其他语...

Common Lisp 中几种常见循环语句(dolist dotimes do)返回值和其他语句的细微差异

目录

0 概述

今天一个下午都在试图定位一个问题:在循环体中生成列表,并且每轮循环都向列表追加数据,最后把列表输出. 结果一直输出为 nil,几经周折,才发现原来问题出在循环语句的使用方式上,自己对 Common Lisp 的循环语句没有透彻理解掌握,只是凭着印象使用.下面详细道来.

1 返回值为 nil 的 dolist 和 dotimes

一般的 Common Lisp 语句,都是把形式体最后一条语句作为返回值,但是形如 dolist 和 dotimes 的循环语句,却不返回,换句话说它们的返回值为 nil, 其实仔细想想就明白为什么要这么规定了, 先看看 dolist 和 dotimes 的语法结构,如下:

(dolist (循环变量 列表-形式)
	循环体)
	
(dotimes (循环变量 数字-形式)
	循环体)

我们发现 dolist 和 dotimes 都是把循环体放在最后面,那么如果要返回值,就涉及一个问题: 返回语句放在哪里? 究竟放在循环体内好呢?还是放在循环体外好?

如果放在循环体内,就会出现每循环一次就返回一个值,如果循环次数很多,就会返回很多值,显然不太合理,如果放在循环体,那它就跟循环语句没有任何联系了.

所以如果想使用 dolist 和 dotimes 来返回某些需要累积的值,就先把这些值在循环体内设置为自我追加的形式,然后保存到一个变量中,最后再用这个变量传递这些值,具体语句可以写成这样:

(let* ((返回列表 nil))
	(dotimes (循环变量 10)
		(setq 返回列表 (append 返回列表 (list 循环变量))))
	返回列表)
	
执行后返回结果如下:
CL-USER> (let* ((返回列表 nil))
			(dotimes (循环变量 10)
				(setq 返回列表 (append 返回列表 (list 循环变量))))
			返回列表)
(0 1 2 3 4 5 6 7 8 9)
CL-USER>

2 返回值不为 nil 的 do

do 这个函数的返回值可以自己设置,不过比较特别的是:它的返回值也不是最后一句,而是在结束条件判断语句后面,具体先看一下 do 的语法形式:

(do ((循环变量1 初值1 步长形式体) (循环变量2 初值2 步长形式体2) …)
	(结束条件形式体 返回结果形式体)
  循环体)

最初我就是没仔细看,所以没注意到它这种比较独特的返回位置,所以花了不少时间来定位,现在清楚了,继续用我们刚才的那个例子,改写为 do 版本如下:

(let* ((返回列表 nil))
	(do ((循环变量 0 (incf 循环变量)))
	    ((>= 循环变量 10) 返回列表)	 
	    (setq 返回列表 (append 返回列表 (list 循环变量)))))
	    
执行结果如下:
CL-USER> (let* ((返回列表 nil))
			(do ((循环变量 0 (incf 循环变量)))
			    ((>= 循环变量 10) 返回列表)	 
			    (setq 返回列表 (append 返回列表 (list 循环变量)))))
(0 1 2 3 4 5 6 7 8 9)
CL-USER> 

3 最后补充说明下 append 函数

append 可以把一个列表追加到另一个列表之后,返回值为新列表,语法如下:

(append list1 list2)			

但是 append 不会修改旧列表,如下代码:

CL-USER> (defparameter l1 `(1 2 3 4))
L1
CL-USER> (defparameter l2 `(5 6 7 8))
L2
CL-USER> (append l1 l2)
(1 2 3 4 5 6 7 8)
CL-USER> l2
(5 6 7 8)
CL-USER> l1
(1 2 3 4)
CL-USER> 

所以如果想把后一个列表追加到前一个列表,还需要手工"赋值"一次,如下:

(setq l1 (append l1 l2))

执行效果如下:
CL-USER> (setq l1 (append l1 l2))
(1 2 3 4 5 6 7 8)
CL-USER> l1
(1 2 3 4 5 6 7 8)
CL-USER> l2
(5 6 7 8)
CL-USER> 

结论: 一定要清楚你所用的语句究竟有没有返回值(也就是返回值是 nil 还是 非 nil), 如果有返回值,那么这条返回语句应该放在什么位置.

可见初学者遇到的很多编程问题都出在对编程语言的误解上,也就是对工具的错误使用上,所以古人说 "工欲善其事,必先利其器", 我们则提倡"多实践,多试错".

转载于:https://my.oschina.net/freeblues/blog/140196

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值