foldr c n
берет список и заменяет каждый (:)
на c
, а последний []
на n
. Но [1..]
не имеет окончательного []
, поэтому foldr (\_ a -> a ++ a) s
не имеет места для размещения s
. Поэтому никакая информация никогда не «перетекает» из s
в результат myCycle s
, что означает, что у нее нет выбора, кроме как быть дном (или, скорее: у нее слишком много выбора - она не указана), поэтому она сдается и возвращается к дно). Вторая версия на самом деле использует s
, потому что она появляется в функции свертывания, которая равна , используемой, когда foldr
действует на бесконечный список.
На самом деле, у нас есть тождество
foldr (\_ -> f) x xs = fix f = let x = f x in x
, когда xs
бесконечно. То есть вторым аргументом foldr
является , полностью игнорируемый , когда список бесконечен. Кроме того, если эта функция свертывания фактически не смотрит на элементы списка, то все, что на самом деле происходит, это то, что вы бесконечно вкладываете f
в себя: fix f = f (f (f (f ...)))
. fix
является фундаментальным в том смысле, что каждый вид рекурсии может быть записан в терминах ее (некоторые более экзотические c виды рекурсии требуют добавления некоторых языковых расширений, но само определение fix f = let x = f x in x
само не меняется). Это делает написание любой рекурсивной функции в терминах foldr
и бесконечного списка тривиальным.
Вот мой взгляд на экспоненциальный цикл. Он создает 1 копию входных данных, объединенную в 2 копии, объединенную в 4 и т. Д. c.
myCycle xs = xs ++ myCycle (xs ++ xs)
Вы явно переводите рекурсивное определение в fix
, абстрагируя рекурсивный вызов в качестве параметра и передавая это fix
:
myCycle = fix \rec xs -> xs ++ rec (xs ++ xs)
И затем вы используете идентификацию foldr
и вводите фиктивный []
кейс
myCycle = foldr (\_ rec xs -> xs ++ rec (xs ++ xs)) (error "impossible") [1..]