Я пытаюсь запомнить процедуру в схеме. Код взят из SICP.
У меня есть моя процедура fib, определенная как
(define (fib n)
(display "computing fib of ")
(display n) (newline)
(cond ((= n 0) 0)
((= n 1) 1)
(else (+ (fib (- n 1))
(fib (- n 2))))))
Моя процедура запоминания выглядит следующим образом
(define (memoize f)
(let ((table (make-table)))
(lambda (x)
(let ((previously-computed-result (lookup x table)))
(or previously-computed-result
(let ((result (f x)))
(insert! x result table)
result))))))
Определим две процедуры
(define mem-fib (memoize fib))
(define mem-fib-lambda (memoize (lambda (n)
(display "computing fib of ")
(display n)
(newline)
(cond ((= n 0) 0)
((= n 1) 1)
(else (+ (memo-fib (- n 1))
(memo-fib (- n 2))))))))
Как видите, в mem-fib я использую fib в качестве аргумента, а в mem-fib-lambda я использую в качестве аргумента лямбда-выражение, что почти идентично.
Вызов этой процедуры с 5 в качестве аргумента дает разные результаты, где первый, mem-fib сохраняет последний результат в своей таблице, тогда как mem-fib-lambda сохраняет все рекурсивные вычисления по пути.
(mem-fib 5)
->computing fib of 5
->computing fib of 4
->computing fib of 3
->computing fib of 2
->computing fib of 1
->computing fib of 0
->computing fib of 1
->computing fib of 2
->computing fib of 1
->computing fib of 0
->computing fib of 3
->computing fib of 2
->computing fib of 1
->computing fib of 0
->computing fib of 1
->5
(mem-fib 5)
->5
а также
(mem-fib-lambda 5)
->computing fib of 5
->computing fib of 4
->computing fib of 3
->computing fib of 2
->computing fib of 1
->computing fib of 0
->5
(mem-fib-lambda 5)
->5
Моя теория состоит в том, что когда я вызываю mem-fib, fib вычисляется в другой среде, тогда как mem-fib-lambda вычисляет ее в той среде, в которой она была вызвана.
В качестве попытки исправить это, я попытался сделать копию в процедуре мемоизации
(define (memoize proc)
(define f proc) ;; Here
(let ((table (make-table)))
(lambda (x)
(let ((previously-computed-result (lookup x table)))
(or previously-computed-result
(let ((result (f x)))
(insert! x result table)
result))))))
Это не сработало, поэтому я попытался поместить это в выражение let. Насколько мне известно, fib должна быть частью того же фрейма, что и таблица.
(define (memoize proc)
(let ((table (make-table))
(f proc)) ;; Here
(lambda (x)
(let ((previously-computed-result (lookup x table)))
(or previously-computed-result
(let ((result (f x)))
(insert! x result table)
result))))))
Это тоже ничего не дало.
Что мне не хватает? Почему есть разница в поведении? Как я могу получить желаемый результат?
Спасибо