¿Por qué recursivo `let` hace que el espacio sea eficiente?

Encontré esta declaración mientras estudiaba la Programación reactiva funcional, de"Enchufar una fuga de espacio con una flecha" por Hai Liu y Paul Hudak (página 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

La diferencia aquí parece pequeña pero aumenta enormemente la eficiencia del espacio. ¿Por qué y cómo sucede? Lo mejor que he hecho es evaluarlos a mano:

    r = \x -> x: r x
    r 3

    -> 3: r 3 
    -> 3: 3: 3: ........
    -> [3,3,3,......]

Como se mencionó anteriormente, necesitaremos crear infinitos trucos nuevos para estas recursiones. Entonces trato de evaluar el segundo:

    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

En la segunda forma laxs aparece y se puede compartir entre todos los lugares en los que ocurre, por lo que supongo que es por eso que solo podemos exigirO(1) espacios en lugar deO(n). Pero no estoy seguro de si estoy en lo correcto o no.

BTW: La palabra clave "compartida" proviene de la misma página 4 del artículo:

El problema aquí es que las reglas de evaluación estándar de llamada por necesidad no pueden reconocer que la función:

f = λdt → integralC (1 + dt) (f dt) 

es lo mismo que:

f = λdt → let x = integralC (1 + dt) x in x

La primera definición hace que el trabajo se repita en la llamada recursiva a f, mientras que en el último caso se comparte el cálculo.

Respuestas a la pregunta(3)

Su respuesta a la pregunta