你的 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
为了避免额外的计算,您真正想要做的是使用动态编程并以自下而上的方式递归。
你想要的是以下代码:
(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 的作用感到困惑,所以让我更好地说明:
当你说:
(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 不会为您做到这一点。