Ответ 1
memoized_fib
является CAF, который так же хорош, как буквальная константа, избегая создания новых вещей. Нет переменных → нет вещей, чтобы связать новый материал с → нет создания нового материала (в упрощенном виде).
Привет. Я рассматриваю этот пример из Memoization:
memoized_fib :: Int -> Integer
memoized_fib = (map fib [0 ..] !!)
where fib 0 = 0
fib 1 = 1
fib n = memoized_fib (n-2) + memoized_fib (n-1)
Мне просто интересно, почему это работает, потому что для меня, если вы вызываете memoized_fib(n-2)
, тогда вы "создаете" новый список и делаете что-то с ним, и после вашего возвращения из него список, содержащий частичный результат, исчезнет? Так что memorized_fib(n-1)
вообще не выиграет от этого?
memoized_fib
является CAF, который так же хорош, как буквальная константа, избегая создания новых вещей. Нет переменных → нет вещей, чтобы связать новый материал с → нет создания нового материала (в упрощенном виде).
Я могу объяснить отсутствующее наблюдение, и это может помочь вам понять поведение, которое вы видите. Важно понять, к чему относятся дескрипторы where
.
Представленный вами код
memoized_fib = (map fib [0 ..] !!)
where fib = ...
который desugars на
memoized_fib = let fib = ...
in \n -> map fib [0 ..] !! n
missingno представил следующее, которое выглядит как простое расширение eta, но это не так!
memoized_fib n = map fib [0 ..] !! n
where fib = ...
desugars to
memoized_fib = \n -> let fib = ...
in map fib [0 ..] !! n
В первом случае вы можете видеть, что структура fib
разделяется между вызовами memoized_fib
, тогда как в последнем случае каждый раз fib
восстанавливается.
Код, который вы показываете, зависит от конкретного поведения компилятора. Здесь desugaring, как Том Эллис, предложил:
memoized_fib =
let fib 0 = 0
fib 1 = 1
fib n = memoized_fib (n-2) + memoized_fib (n-1)
in
(map fib [0 ..] !!)
Ничто не гарантирует, что список map fib [0..]
будет повторно использован, то есть "общий". Особенно, когда вы опускаете подпись типа, как и я, делая это полиморфным определением.
Лучше сделать этот список явным, указав ему имя:
memoized_fib n =
let fib 0 = 0
fib 1 = 1
fib n = g (n-2) + g (n-1)
g = (fibs !!)
fibs = map fib [0 ..]
in
g n
Это было обсуждено до.