Lisp 循环:loop、do、mapcar
掌握 Lisp 循环是提高编程效率的关键。Lisp 提供了多种循环构造,每种都有其独特用途。本文将详细介绍 loop、do 和 mapcar 三种主要循环方法。
loop 构造
loop 是 Lisp 中最强大、最灵活的循环构造,它提供了丰富的语法来完成各种迭代任务。
基本语法:
(loop for <变量> from <起始> to <结束> do <表达式>)
创建 一个简单的计数循环:
(loop for i from 1 to 5 do
(print i))
执行 结果将打印数字 1 到 5。
loop 高级用法
使用 收集子句存储结果:
(loop for i from 1 to 5
collect (* i i))
生成 包含平方值的列表:(1 4 9 16 25)
添加 条件筛选:
(loop for i from 1 to 10
when (evenp i)
collect i)
返回 偶数列表:(2 4 6 8 10)
组合 多种条件:
(loop for x from 1 to 10
for y from 10 downto 1
when (< x y)
collect (list x y))
产生 所有 x < y 的配对列表。
使用 终止条件:
(loop for i from 1
when (> i 10)
return i
do (print i))
打印 1 到 10 后返回值 11。
do 构造
do 是 Lisp 中传统的循环构造,类似于其他编程语言中的 for 循环,结构清晰直观。
基本语法:
do ((<变量1> <初始值1> <更新表达式1>)
(<变量2> <初始值2> <更新表达式2>)
...)
(<终止条件> <返回值>)
<循环体>)
创建 简单计数循环:
(do ((i 1 (+ i 1)))
((> i 5) nil)
(print i))
打印 数字 1 到 5。
实现 累加功能:
(do ((sum 0 (+ sum i))
(i 1 (+ i 1)))
((> i 10) sum)
(print i))
计算 1 到 10 的和并返回结果。
处理 多个变量:
(do ((x 1 (+ x 1))
(y 10 (- y 1)))
((> x y) (list x y))
(format t "~a ~a~%" x y))
显示 x 和 y 的值,直到 x 大于 y。
使用 终止条件:
(do ((i 1)
(result nil))
((null result) result)
(if (> i 10)
(setf result (list i))
(print i)))
返回 当 i 大于 10 时的列表。
mapcar 函数
mapcar 是一种函数式编程风格的"循环",它对列表中的每个元素应用函数并返回结果列表。
基本语法:
mapcar '<函数> '<列表1> '<列表2> ...)
应用 单个列表:
(mapcar #'(lambda (x) (* x x)) '(1 2 3 4 5))
返回 平方值列表:(1 4 9 16 25)
处理 多个列表:
(mapcar #'+ '(1 2 3) '(4 5 6))
返回 对应元素和的列表:(5 7 9)
组合 复杂函数:
(mapcar #'(lambda (x y) (list x y (* x y)))
'(1 2 3)
'(4 5 6))
返回 包含元素及其乘积的列表:((1 4 4) (2 5 10) (3 6 18))
用于 转换数据结构:
(mapcar #'(lambda (person)
(list (first person)
(getf (rest person) :age)))
'((john :age 25)
(mary :age 30)
(bob :age 18)))
提取 每个人的姓名和年龄。
三种循环比较
三种循环方式各有特点,适合不同场景:
| 特点 | loop | do | mapcar |
|---|---|---|---|
| 用途 | 通用迭代,复杂循环结构 | 传统循环,变量控制迭代 | 函数式编程,列表处理 |
| 语法复杂度 | 中等,需要学习子句 | 简单,类似传统for循环 | 非常简单 |
| 可读性 | 高,表达意图明确 | 高,结构清晰 | 高,函数式风格 |
| 功能范围 | 最广,支持各种迭代 | 中等,基本迭代功能 | 较窄,主要用于列表处理 |
| 性能 | 一般,抽象层次高 | 较好,结构化程度高 | 良好,针对列表优化 |
选择 循环方式:
- 当需要复杂条件判断和多种操作时,使用
loop - 当需要传统计数循环时,选择
do - 当处理列表转换时,采用
mapcar
实际应用示例
处理 文件中的每行:
(with-open-file (stream "data.txt" :direction :input)
(loop for line = (read-line stream nil nil)
while line
do (process-line line)))
读取 文件并处理每行内容。
计算 列表元素统计:
(let ((numbers '(3 1 4 1 5 9 2 6)))
(list :count (length numbers)
:sum (reduce #'+ numbers)
:average (/ (reduce #'+ numbers) (length numbers))))
返回 列表的计数、总和和平均值。
应用 多个转换步骤:
(let ((data '("1" "2" "3" "4" "5")))
(mapcar #'(lambda (x)
(* (parse-integer x) 2))
(mapcar #'(lambda (x)
(concatenate 'string "Num-" x))
data)))
转换 字符串为数字并乘以2,结果:(2 4 6 8 10)
组合 循环方式处理复杂数据:
(let ((data '((a 1) (b 2) (c 3) (d 4))))
(loop for item in data
for key = (first item)
for value = (second item)
when (evenp value)
collect (list key (* value value))))
筛选 偶数值并返回键值对,平方处理后的结果:((b 4) (d 16))

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