如何用Common Lisp编写生成升序数字列表的优雅程序?
实现从0到指定数字的列表(Common Lisp)
先说说你现有实现的问题
- 第一个
counter函数依赖闭包里的可变变量a和lis,存在副作用:多次调用时变量会保留上一次的状态。比如第一次调用(counter 3)返回(0 1 2),第二次调用(counter 2)会返回(3 4),完全不符合预期,且偏离了Lisp推崇的纯函数风格。 - 第二个
counter2函数仅做递归打印,没有收集结果。只需把打印逻辑替换成列表构建操作,就能实现需求。
优雅的实现方式
1. 用loop宏(最简洁实用)
Common Lisp的loop宏功能强大,一行代码就能搞定:
(defun counter (n) (loop for i from 0 to n collect i))
调用(counter 5)会返回(0 1 2 3 4 5),这是最贴合Lisp实用主义风格的写法,简洁且可读性拉满。
2. 纯函数递归实现(函数式风格)
如果想练习递归,可以写一个无副作用的纯函数版本。这里用尾递归(编译器通常会优化为循环,效率更高):
(defun counter (n) ;; 定义内部辅助函数,传递当前计数和结果列表 (labels ((helper (current acc) (if (< current 0) acc ;; 递归终止,返回收集好的列表 (helper (- current 1) (cons current acc))))) (helper n '()))) ;; 从n往0递归,最终得到0到n的列表
这个版本没有全局/闭包可变变量,每次调用都是独立的,完全符合函数式编程要求。
3. 改造你的第二个递归思路
可以把counter2改成先收集从n到0的列表,再反转得到目标结果:
(defun counter2 (x) (if (< x 0) '() (cons x (counter2 (- x 1))))) ;; 调用时反转结果 (reverse (counter2 5)) ;; 返回(0 1 2 3 4 5)
或者调整递归方向,从0开始构建列表:
(defun counter2 (x) (labels ((helper (current acc) (if (> current x) acc (helper (+ current 1) (cons current acc))))) (reverse (helper 0 '()))))
内容的提问来源于stack exchange,提问作者Mattias Smedstad
相关产品推荐
相关产品推荐

