Почему рекурсивный `пусть` делает пространство эффективным?
Я нашел это утверждение во время изучения функционально-реактивного программирования, изЗаглушить космическую утечку со стрелкой " Хай Лю и Пол Худак (стр. 5):
Suppose we wish to define a function that repeats its argument indefinitely:
repeat x = x : repeat x
or, in lambdas:
repeat = λx → x : repeat x
This requires O(n) space. But we can achieve O(1) space by writing instead:
repeat = λx → let xs = x : xs
in xs
Разница здесь небольшая, но она очень сильно влияет на эффективность использования пространства. Почему и как это происходит? Лучшее предположение яМы сделали, чтобы оценить их вручную:
r = \x -> x: r x
r 3
-> 3: r 3
-> 3: 3: 3: ........
-> [3,3,3,......]
Как и выше, для этих рекурсий нам нужно будет создать бесконечные новые громы. Затем я пытаюсь оценить второй:
r = \x -> let xs = x:xs in xs
r 3
-> let xs = 3:xs in xs
-> xs, according to the definition above:
-> 3:xs, where xs = 3:xs
-> 3:xs:xs, where xs = 3:xs
Во второй формеxs
появляется и может быть разделен между всеми местами, где это происходит, поэтому я думаю, чтопочему мы можем требовать толькоO(1)
пробелы, а неO(n)
, Но я'я не уверен, что яЯ прав или нет.
Кстати: ключевое словообщий" исходит из той же бумаги "страница 4:
Проблема здесь в том, что стандартные правила оценки по требованию не могут распознать, что функция:
f = λdt → integralC (1 + dt) (f dt)
такой же как:
f = λdt → let x = integralC (1 + dt) x in x
Бывший дефиnition вызывает повторение работы при рекурсивном вызове f, тогда как в последнем случае вычисление разделяется.