Common Lisp中DO循环输出与预期不符的原因及执行流程解析
Common Lisp
do 循环执行流程与输出解析 原代码
(setq x 10) (setq y 30) (do ((x 0 (+ 3 x)) (y 20 (- y 2)) (z (- y x) (- z x))) ((> x y) (- x y)) ; exit condition (format t "~% z = ~d" z)) ; print local variable Z (format t "x = ~d y = ~d" x y) ; print global variables X and Y
预期输出
z = 20 z = 17 z = 11 z = 2 z = -10 x = 15 y = 10
疑惑解答
1. 迭代过程中变量x、y、z是如何更新的?
Common Lisp的do循环采用并行绑定规则处理迭代变量:
- 初始化阶段:所有变量的初始值同时计算,若引用外部变量(比如
z的初始值(- y x)),会使用全局变量的值(此时局部变量还未绑定)。 - 更新阶段:每次循环体执行后,所有变量的新值基于上一轮迭代结束时的旧值并行计算——也就是说,某变量的新值不会影响同一轮其他变量的更新计算。
- 注意:
do内的x、y是局部变量,和全局的x、y完全独立,不会互相干扰。
2. 为何我的预期输出不正确?
你的预期错误源于两个核心误解:
- 误解了
do的变量更新逻辑:你以为变量是顺序更新的(比如先更新x,再用新x计算z的新值),但实际是并行更新,所有更新表达式都使用上一轮的旧值。 - 混淆了局部变量和全局变量:你以为
do内的x、y会修改全局变量,但do的迭代变量是局部绑定的,循环结束后全局变量的值不会改变。
3. 正确输出是什么,原因是什么?
正确输出:
z = 20 z = 20 z = 17 z = 11 z = 2 x = 10 y = 30
执行流程解析:
- 全局变量初始化:
x=10,y=30。 do循环局部变量初始化:- 局部
x=0,局部y=20,局部z=全局y-全局x=30-10=20。
- 局部
- 第一次循环:
- 退出条件
(>0 20)为假,执行循环体,打印z = 20。 - 并行计算更新值:新
x=0+3=3,新y=20-2=18,新z=20-0=20(用上一轮旧值计算)。
- 退出条件
- 第二次循环:
- 退出条件
(>3 18)为假,执行循环体,打印z = 20。 - 并行计算更新值:新
x=3+3=6,新y=18-2=16,新z=20-3=17。
- 退出条件
- 第三次循环:
- 退出条件
(>6 16)为假,执行循环体,打印z = 17。 - 并行计算更新值:新
x=6+3=9,新y=16-2=14,新z=17-6=11。
- 退出条件
- 第四次循环:
- 退出条件
(>9 14)为假,执行循环体,打印z = 11。 - 并行计算更新值:新
x=9+3=12,新y=14-2=12,新z=11-9=2。
- 退出条件
- 第五次循环:
- 退出条件
(>12 12)为假,执行循环体,打印z = 2。 - 并行计算更新值:新
x=12+3=15,新y=12-2=10,新z=2-12=-10。
- 退出条件
- 退出判断:
- 退出条件
(>15 10)为真,循环结束,不执行循环体。
- 退出条件
- 最后打印全局变量:
x=10,y=30(局部变量不影响全局)。
内容的提问来源于stack exchange,提问作者Hasan Saafen
相关产品推荐
相关产品推荐

