Scheme 循环:do、for-each、map
Scheme 语言没有传统意义上的 while 或 for 循环,而是通过递归和内置的迭代结构实现重复操作。掌握 do、for-each 和 map 是写出简洁高效代码的关键。以下指南将手把手教你正确使用这三种结构。
使用 do 实现通用循环
do 是 Scheme 中最接近传统循环的结构,适合需要显式控制变量更新和终止条件的场景。
-
理解基本语法:
do的格式为(do ((var init update) ...) (test result ...) body ...)其中
var是循环变量,init是初始值,update是每次迭代后的更新表达式;test为真时循环结束,此时返回result ...的值;body ...是每次迭代执行的操作。 -
编写一个从 0 到 n-1 的计数循环:
定义 变量i初始为0,每次加1,当i等于n时停止。(define (count-up n) (do ((i 0 (+ i 1))) ((= i n)) (display i) (newline)))调用
(count-up 3)将输出:0 1 2 -
在循环中累积结果:若需返回计算值(而非仅副作用),把结果放在
test子句后。例如计算阶乘:(define (factorial n) (do ((i 1 (+ i 1)) (acc 1 (* acc i))) ((> i n) acc)))此处
acc初始为1,每次乘以当前i,当i超过n时返回acc。
使用 for-each 执行副作用
当你有一组数据,只需对每个元素执行操作(如打印、写文件),不关心返回值时,用 for-each。
-
确认输入是一个列表:
for-each只能遍历列表(或其他序列类型,取决于 Scheme 实现),不能直接用于数字范围。 -
提供一个过程和一个或多个列表:
调用(for-each proc list1 list2 ...),其中proc接受与列表数量相同的参数。(for-each display '(a b c))输出:
abc(无换行)。 -
处理多列表并行遍历:
(for-each (lambda (x y) (display x) (display ": ") (display y) (newline)) '(apple banana cherry) '(red yellow red))输出:
apple: red banana: yellow cherry: red注意:所有列表必须等长,否则行为未定义。
使用 map 转换数据并收集结果
map 用于对列表每个元素应用函数,并返回新列表,是函数式编程的核心工具。
-
单列表变换:
应用 函数到每个元素,生成结果列表。(map (lambda (x) (* x x)) '(1 2 3 4))返回:
'(1 4 9 16)。 -
多列表并行映射:
(map + '(1 2 3) '(10 20 30))返回:
'(11 22 33)。函数+同时接收两个列表的对应元素。 -
避免副作用:虽然技术上可在
map中使用display等副作用操作,但这是反模式。坚持只在map中做纯变换,用for-each处理副作用。
选择正确的循环结构
根据你的目标决定使用哪种结构:
| 场景 | 推荐结构 | 原因 |
|---|---|---|
| 需要精细控制循环变量和终止条件 | do |
提供完整的初始化、测试、更新机制 |
| 对每个元素执行操作但不需要返回值(如打印) | for-each |
语义清晰,明确表示只用于副作用 |
| 将列表转换为另一个列表 | map |
自动收集结果,符合函数式风格 |
记住:在 Scheme 中,优先使用 map 和 for-each;仅当它们无法满足需求(如需要多个状态变量或复杂终止逻辑)时才用 do。

暂无评论,快来抢沙发吧!