如何为Scheme的fixed-point函数添加迭代计数器 正确实现方案有哪些
实现正确性说明
你现有的两种写法都可以正确统计迭代次数:
- 第一种搭配
set!修改外部变量的写法属于命令式实现,逻辑没问题,但引入了可变状态,不符合函数式编程的惯用法。 - 第二种把计数器作为迭代函数参数传递的写法是纯函数式实现,没有可变变量,逻辑更干净。
用let实现的方案
你提到的用let实现可以通过Scheme的命名let(named let) 语法完成,这也是Scheme里编写迭代循环的常用写法,示例代码如下:
(define tolerance 0.01) (define (close-enough? x y) (< (abs (- x y)) 0.001)) (define (fixed-point function starting-guess) ; 命名let语法:let 函数名 ((参数 初始值) ...) 函数体 (let evaluate ((num starting-guess) (iteration-num 1)) ; 初始值设为1和你第一种set!写法的计数结果对齐,要和第二种写法对齐则设为0 (display iteration-num) (display " - ") (display num) (display "\n") (let ((next-num (function num))) (if (close-enough? num next-num) next-num (evaluate next-num (+ 1 iteration-num)))))) (fixed-point cos 1.0)
命名let本质是语法糖,和你第二种内部定义evaluate函数再传入初始参数的写法完全等价,只是写法更紧凑,不需要单独写内部define和初始调用语句。
推荐方案
优先选择无可变状态的函数式实现,也就是你第二种传参的写法或者上述命名let写法,原因如下:
- 没有
set!带来的可变变量,不存在意外修改变量的风险,代码可预测性更强 - 完全符合Scheme的函数式编程范式,可读性和可维护性更好
- 调试更方便,每次迭代的状态都完全体现在参数里,不需要追踪外部变量的变化
只有当你确实需要在多个不同逻辑分支修改计数、或者有其他必须用到可变状态的场景时,再考虑用set!的实现。
内容的提问来源于stack exchange,提问作者David542
相关产品推荐
相关产品推荐

