(define fibo ; fibonacci
(lambda (n)
(cond ((= n 0) 0)
((= n 1) 1)
((= n 2) 1)
(else (+ (fibo (- n 1)) (fibo(- n 2))
)))))
(time (fibo 20))
(define (fiboN n) ; fibonacci
(delay (cond ((= n 0) 0)
((= n 1) 1)
((= n 2) 1)
(else (+ (force (fiboN (- n 1))) (force (fiboN(- n 2))))))))
(time force( force (fiboN 20)))
考虑到上面的两个斐波纳契函数,我预计第二个会运行得更快,因为方案在强制延迟对象上应用了memoization。
然而第二个纤维运行速度较慢。那为什么会这样?我对Scheme中的自动记忆错了吗?
答案 0 :(得分:3)
你将记忆与延迟(a.k.a. 懒惰)评估相混淆 - 看一下这个explanation来理解这两个概念之间的区别。
你的fiboN
的第二次实现当然是延迟的,但它并没有记忆任何东西 - 当然,一旦我们force
一个值,它就不会再被强制了,但它不会改变这是一个递归函数的事实,它被我们已经获得的值一遍又一遍地调用,延迟/强制每个值的额外成本将使它比第一个实现慢。
这是一个真正使用memoization的可能实现,诀窍是将已经计算好的值保存在我们可以有效访问它们的地方 - 本例中的哈希表:
(define fiboN
(let ((memo (make-hash '((0 . 0) (1 . 1)))))
(lambda (n)
(unless (hash-has-key? memo n)
(hash-set! memo n (+ (fiboN (- n 1)) (fiboN (- n 2)))))
(hash-ref memo n))))
结果显示这要快得多:
(time (fiboN 100))
cpu time: 0 real time: 1 gc time: 0
354224848179261915075