Programming Clojure学习笔记——函数编程

本文探讨了递归函数的实现方式及其优化方法,包括相互递归的四种解决方案:转换为自递归、使用trampoline函数、利用延迟计算以及通过缓存减少重复计算。并通过具体实例展示了如何解决递归过程中的堆栈溢出问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5.4 再谈递归
相互递归:两个或两个以上函数之间互相调用。如:
(declare my-odd? my-even?)
(defn my-odd? [n]
     (if (= n 0)
         false
         (my-even? (dec n))))
(defn my-even? [n]
     (if (= n 0)
         true
         (my-odd? (dec n))))

有四种方法解决这种互相调用递归计算问题:
(1) 转换为自递归,即函数自己调用自己
找出各个函数之间的共性,定义一个公共的递归函数,被各个函数调用得到各自返回值

(2) 利用Clojure的trampoline函数执行递归计算
(trampoline f & partial-args)
如果返回值不是函数,则直接像调用函数一样执行,如
(trampoline + 1 2) # 返回 3
如果返回值是函数,则递归调用函数直到返回值不是函数为止。
说明:对于相互调用的递归函数内部调用其他函数的语句前需要加#号,标识为匿名函数。
如上面的函数修改为:
(declare my-odd? my-even?)
(defn my-odd? [n]
     (if (= n 0)
         false
         #(my-even? (dec n))))
(defn my-even? [n]
     (if (= n 0)
         true
         #(my-odd? (dec n))))
通过trampoline函数计算值:
user=> (trampoline my-even? 1000000)
true

(3) 使用延迟替换递归
(4) 通过缓存加快递归
解决如下问题:
F(0) = 1; M(0) =0;
F(n) = n - M(F(n-1)), n > 0
M(n) = n - F(M(n-1)), n > 0
计算M(10000)

定义函数:
(declare m f)
(defn m [n]
     (if (zero? n) 0 (- n (f (m (dec n))))))
(defn f [n]
     (if (zero? n) 1 (- n (m (f (dec n))))))
直接计算M(10000)会出现堆栈溢出

利用Clojure的memorize函数,将m和f函数变成带缓存版本:
(def m (memoize m))
(def f    (memoize f))
此时直接计算M(10000)也会出现堆栈溢出

以序列代替函数:
(def m-seq (map m (iterate inc 0)))
(def f-seq    (map f (iterate inc 0)))
此时计算M(10000),即取序列m-seq的第10000个元素:
(nth m-seq 10000) 返回 6180
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值