2015-05-17 17 views
5

Kiedy biegnę (println (iterate inc 0)) w moim repl, będę się mniej więcej tak:(println (iterate inc 0)): dlaczego to nawet rozpoczyna drukowanie?

user=> (println (iterate inc 0)) 
(0 1 2 3 4 5 6 7 8 9 10 11 12 13 .................... 

moje oczekiwania kiedy uruchomić kod jest repl pokazuje nic i po prostu utknął bo (iterate inc 0) nigdy się nie kończy. Ale widzę (0 1 2 3 ....

generuje nieskończoną sekwencję, która nigdy nie powraca. Jeśli to się nigdy nie kończy, dlaczego println zaczyna drukować wartości?

Innymi słowy, dlaczego (println xx) zaczyna być oceniane, nawet jeśli dane wejściowe nigdy nie zostały zakończone, gdy są oceniane?

+1

'println' nie trzeba całą sekwencję być zrealizowane przed drukowaniem , robi to na żądanie. "który nigdy nie wraca". '(first (iterate inc 0))' zwróci ci '0' z tego samego powodu. – zerkms

Odpowiedz

8

Powinieneś przeczytać na w Clojure. Są w stanie wytworzyć wartości, które mogą być konsumowane przyrostowo, zanim cała sekwencja zostanie zrealizowana (co w tym przypadku nigdy nie nastąpi).

To może pomóc myśleć o tym jako push vs pull. Zamiast iterować, tworząc całą listę wartości, a następnie przesuwając je do funkcji println (która nigdy by się nie wydarzyła), iteracja po prostu przekazuje ją leniwej sekwencji, a println ściąga wartości według potrzeb. Dlatego działa (weź 5 (iteracyjne przejście 0)); przed zatrzymaniem próbuje jedynie wyciągnąć 5 wartości.

2

Drukowanie Clojure jest mądrzejsze niż System.out.println; może to być customized for different types. W przypadku sekwencji walks through element-by-element, printing each one as it goes - nie musimy czekać, aż cała sekwencja zostanie oceniona, aby rozpocząć drukowanie.

W przeciwieństwie do tego, System.out.println, który przed wydrukowaniem wywołuje toString, zachowuje się bardziej, jak można się spodziewać. Wisi na zawsze, nie drukuje niczego, ponieważ toString musi ocenić całą sekwencję - lub przynajmniej zawiesiłby się na zawsze, gdyby nie zabrakło pamięci próbując zbudować ciąg.

Powiedział, że całe wyrażenie jest rzeczywiście zatrzymany - jeśli czekali na to, aby zatrzymać drukowanie, można czekać w nieskończoność:

(do 
    (println (iterate inc 0)) 
    (println "Never reached!"))