你的 let 并没有真正做任何事情。您仍在进行所有额外的计算。仅仅因为您将 f1 定义为 (fib-with-let (- n 1)) 并不意味着您不会再次计算 n-1 的 fib。 f2不使用f1。如果您希望 f2 能够查看 f1,您可以使用 let*。然而,即使这也不是你真正想要的。
以下是运行时间for fib(35) 和fib-with-let(35):
(time (fib 35))
cpu time: 6824 real time: 6880 gc time: 0
(time (fib-with-let 35))
cpu time: 6779 real time: 6862 gc time: 0
您真正想要避免额外计算的做法是使用 dynamic programming 并在 bottom-up fashion 中递归。
你想要的是下面的代码:
(define (dynprog-fib n)
(if (< n 2)
n
(dynprog-fib-helper 1 1 2 n)))
(define (dynprog-fib-helper n1 n2 current target)
(if (= current target)
n2
(dynprog-fib-helper n2 (+ n1 n2) (add1 current) target)))
(time (dynprog-fib 35))
cpu time: 0 real time: 0 gc time: 0
(time (dynprog-fib 150000))
cpu time: 2336 real time: 2471 gc time: 644
如您所见,您可以在幼稚方法所用时间的三分之一内完成前 150,000 个谎言。
因为您似乎对让我更好地说明什么感到困惑:
当你说:
(let ((a 1)
(b 2))
(+ a b))
您的意思是,让 a 为 1,b 为 2,将它们加在一起。
如果你说:
(let ((a 1)
(b (+ a 1))
(+ a b))
你能猜出你会得到什么吗?不是 3. 它会被 expand: unbound identifier in module in: a 炸毁
在简单的let 中,您的作业不能看到彼此。
如果您想编写以上内容,则必须使用let*:
(let* ((a 1)
(b (+ a 1))
(+ a b))
这会给你你所期望的 3。 let* 本质上扩展为:
(let ((a 1))
(let ((b (+ a 1)))
(+ a b)))
您认为您使用 let 执行的操作称为 memoization。这是一种存储中间值的技术,因此您不必重复它们。但是,Let 不会为您做到这一点。