Вопрос возник в связи с реализацией известной функции Хофштадтера на Питоне
с использованием мемоизации. Но можно начать и с обычных чисел Фибоначчи.
Определим:
F(n) = F(n-1) + F(n-2)
Что не так в этом определении?
Здесь нет начальных условий!
Получается, мы начинаем с пустого словаря
memo_dict = {}
И если начать с n = 1, то первый же запрос F(n-1) выдаст ошибку
KeyError.
Да, но у нас же есть перегрузка методов! Перепишем
__missing__
так, чтобы при запросе на несуществующий ключ не выдавалась ошибка, а ему присваивалось бы определенное default значение, скажем 1.
Таким образом, первое обращение к функции потребует принудительного добавления в словарь {-1: 1, 0: 1}
Рекурсия в некотором смысле «нырнет в неизвестное», но потом все продолжится естественным образом! Вычисление каждого нового значения будет использовать уже созданный словарь. Глубина «погружения» в неопределенность окажется равной 2.
Теперь обратимся к
QHofstadter
Q(n) = Q(n - Q(n-1)) + Q(n - Q(n-2))
Начав с пустого словаря, n = 3 и default = 1, все произойдет также, как и для Фибоначчи:
возникнут классические начальные условия {1: 1, 2: 1} и далее все по плану.
Мне очень любопытно, есть ли какие-то статьи и исследования о таком подходе к рекурсии?
То, что он не тривиален, легко убедится на примере той же QHofstadter.
Начнем со словаря {1: 2, 2: 1}. На третьем шаге рекурсия «нырнет» к неопределенному ключу 0, но потом опять пойдет вперед самостоятельно. Пробуя другие, небольшие целочисленные начальные значения, мы увидим самые разнообразные примеры «погружения в неизвестное»:
{1: 5, 2: 6}
{1: 4, 2: 5}
{1: 8, 2: 3}
Мне бы хотелось продолжить исследования, но возможно, эта тема уже давно раскрыта.
Буду признателен за любые комментарии и ссылки!