文章目录

Lisp 循环:loop、do、mapcar

发布于 2026-04-15 17:15:01 · 浏览 17 次 · 评论 0 条

Lisp 循环:loop、do、mapcar

掌握 Lisp 循环是提高编程效率的关键。Lisp 提供了多种循环构造,每种都有其独特用途。本文将详细介绍 loopdomapcar 三种主要循环方法。

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))

评论 (0)

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

扫一扫,手机查看

扫描上方二维码,在手机上查看本文