Il tuo problema qui sembra essere specificamente intorno alle sequenze di Clojure che possono essere infinite.
Le sequenze di Clojure possono essere nulle o implementare un'interfaccia chiamata ISeq, che tra le altre cose ha 2 funzioni particolarmente importanti, first
e next
.
Considera la seguente classe java
public class LongsFrom implements ISeq{
private Long _currentNumber;
public LongsFrom(Long start){
_currentNumber = start
}
public Object first(){
return _currentNumber;
}
public ISeq next(){
return new LongsFrom(_currentNumber + 1);
}
}
Rappresenta una sequenza infinita di numeri crescenti che iniziano dove vuoi tu. Mentre continui a chiamare next () su di esso, continui a realizzare sempre più sequenze, tuttavia tutto quello che devi veramente tenere in memoria è qualunque sia l'ultimo oggetto nella sequenza.
Che ciclo fa creare un'istanza di una classe che implementa l'interfaccia ISeq (sa come calcolare la sequenza ma in realtà non lo fa fino a quando non inizierai a chiamare in seguito). Quindi il tuo comando take
inizia effettivamente a chiamare first
e rest
su questa classe per ottenere comunque gran parte della sequenza di cui ha bisogno.
Una classe che esegue effettivamente cycle
sarebbe solo leggermente più complicata del mio esempio LongsFrom. La classe del ciclo potrebbe avere 2 variabili private, una che contiene l'elenco delle cose che deve scorrere e quindi un intero per ricordare quale indice è attualmente attivo. per prima cosa restituirebbe l'articolo nell'indice corrente. next restituirebbe un nuovo oggetto ciclo con la stessa lista interna esatta, ma un indice di 1 + currentIndex (a meno che non siamo alla fine della lista, nel qual caso iniziamo di nuovo l'indice a 0)
Il motivo per cui hai problemi di memoria se non hai il comando take
è che se non hai il comando take
, il repl prova a print
la sequenza e l'implementazione predefinita per print
è di continuare a chiamare first
e rest
fino alla fine della sequenza (che non è mai nel caso di cycle
)