You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Common Lisp宏中LOOP转DO的实现优化及写法合理性问询

关于将Common Lisp宏中LOOP转换为DO的疑问

问题背景

我正在阅读Seibel所著的《Practical Common Lisp》,发现如下示例宏:

(defmacro check (&rest forms)
 `(progn
     ,@(loop for f in forms collect `(do-stuff ,f ',f))

(defun test ()
    (check ( (= (+ 1 2 ) 3) (= (+ 1 2 ) 4 )))
 )

注:do-stuff仅用于格式化两个参数以测试表达式的真值,与问题无关。

我希望将其中的LOOP转换为DO,已自行实现两种可行方案:

方案一

(defmacro check (&rest forms)
`(progn
    ,@(do ((index 0 (list-length forms))
            (accumulator nil))
        ((= index (list-length forms)) accumulator)
         (push `(do-stuff ,(nth index forms) ',(nth index forms)) accumulator)
         ))

方案二

(defmacro check (&rest forms)
`(progn
    ,@(do* ((index 0 (list-length forms))
            (accumulator nil)
            (f (nth index forms) (nth index forms)))
        ((= index (list-length forms)) accumulator)
         (push `(do-stuff ,f ',f) accumulator)
         ))

我的疑问:

  • 是否存在更高效的DO循环写法?
  • 当前实现是否合理?
  • 能否像LOOP版本那样,无需定义索引变量和累加器列表即可提取列表元素并收集结果?

解答

1. 当前实现的合理性

你的两种方案既存在逻辑错误,又有性能问题:

  • 逻辑错误:索引更新表达式写错了——你用(list-length forms)作为index的增量,这会让index直接跳到列表长度,循环只会执行一次,无法遍历所有forms元素。正确的增量应该是(1+ index)。
  • 性能问题:每次循环调用list-length和nth都会遍历整个列表,时间复杂度从O(n)变成O(n²),元素越多效率越低。

2. 更高效的DO写法

正确且高效的DO写法应该直接遍历列表,避免索引间接访问:

(defmacro check (&rest forms)
  `(progn
     ,@(do ((remaining forms (cdr remaining))
            (acc nil))
           ((null remaining) (reverse acc))
         (push `(do-stuff ,(car remaining) ',(car remaining)) acc))))

这个版本的优势:

  • 用remaining跟踪未处理的列表元素,每次取car获取当前元素,cdr推进循环,都是O(1)操作,整体时间复杂度O(n)。
  • 仅保留必要的循环变量,逻辑清晰,性能和原LOOP版本一致。
  • 最后用reverse修正push导致的逆序问题,确保生成代码的顺序和输入forms一致。

3. 能否像LOOP那样省略索引和累加器?

DO是显式控制结构,必须声明循环变量和终止条件,无法做到LOOP那种高度抽象的语法。不过上面的优化版本已经去掉了索引变量,仅保留了剩余列表和累加器,这是DO结构下的最简形式。

如果追求更简洁的替代方案,mapcar是更好的选择,语义和原LOOP完全一致,代码更短:

(defmacro check (&rest forms)
  `(progn
     ,@(mapcar (lambda (f) `(do-stuff ,f ',f)) forms)))

内容的提问来源于stack exchange,提问作者AVALFINN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 13:45:24