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

来源:互联网 发布:it服务 编辑:程序博客网 时间:2024/06/06 01:15
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
原创粉丝点击