Clojure: ленивая магия

Почти 2 идентичные программы для генерации бесконечных ленивых последовательностей рандомов. Первый не вылетает. Второй сбой с исключением OutOfMemoryError. Почему?

;Return infinite lazy sequence of random numbers    
(defn inf-rand[] (lazy-seq (cons (rand) (inf-rand))))    

;Never returns. Burns the CPU but won't crash and lives forever.    
(last (inf-rand))

Но следующий сбой довольно быстро:

;Return infinite lazy sequence of random numbers    
(defn inf-rand[] (lazy-seq (cons (rand) (inf-rand))))    
(def r1 (inf-rand))

;Crash with "OutOfMemoryError"
 (last r1)

person GabiMe    schedule 18.11.2009    source источник


Ответы (1)


Я считаю, что это пример «держаться за голову».

Делая ссылку r1 во втором примере, вы открываете возможность позже сказать что-то вроде (first r1), так что в конечном итоге вы сохраните члены вашего lazy-seq по мере их овеществления.

В первом случае Clojure может определить, что с более ранними членами бесконечной последовательности ничего не будет сделано, поэтому их можно удалить и не потреблять память.

Я все еще новичок в Clojure, поэтому любые комментарии или исправления моего понимания или терминологии будут очень признательны.

person Alex Stoddard    schedule 18.11.2009
comment
Я тоже новичок, но ваше объяснение выглядит очень правильно. Я бы ответил тем же, если бы ты меня не опередил! И 6 голосов, кажется, согласны с вами. - person Carl Smotricz; 18.11.2009
comment
Когда некоторое время назад я начал решать задачи Project Euler в Clojure, мои отладочные отпечатки на бесконечных ленивых последовательностях замедляли мои программы... бесконечно. Бесконечные ленивые последовательности — важная концепция Clojure, с которой нужно разобраться. - person Carl Smotricz; 18.11.2009
comment
Кстати, почему нет StackOverflow. Существует бесконечная рекурсия в inf-rand - person GabiMe; 19.11.2009
comment
Нет переполнения стека, потому что ленивая оценка не рекурсивно стека. Каждый элемент оценивается и возвращается. - person Eric Normand; 24.11.2009