Ho trovato questa dichiarazione mentre studiava funzionale programmazione reattiva, da "Plugging a Space Leak with an Arrow" da Hai Liu e Paul Hudak (pagina 5):Perchè ricorsivo "lasciamo" rendere lo spazio effciente?
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 differenza qui sembra piccola, ma viene richiesto enormemente l'efficienza dello spazio. Perché e come succede? L'ipotesi migliore che ho fatto è quello di valutare loro mano:
r = \x -> x: r x
r 3
-> 3: r 3
-> 3: 3: 3: ........
-> [3,3,3,......]
Come sopra, avremo bisogno di creare infiniti nuovi thunk per queste ricorsione. Poi cerco di valutare il secondo:
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
Nella seconda forma gli appare xs
e possono essere condivisi tra tutti i luoghi che si verificano, quindi credo che sia il motivo per cui siamo in grado di richiedere solo O(1)
spazi piuttosto che O(n)
. Ma non sono sicuro se ho ragione o no.
BTW: La parola chiave "condivisa" viene dalla stessa del giornale pagina 4:
Il problema qui è che le regole di valutazione standard di Call-by-necessità non sono in grado di riconoscere che la funzione:
f = λdt → integralC (1 + dt) (f dt)
è lo stesso:
f = λdt → let x = integralC (1 + dt) x in x
l'ex definizione fi cause di lavoro per essere ripet ted nella chiamata ricorsiva a f, mentre in quest'ultimo caso il calcolo è condiviso.