Il classico esempio della sequenza infinita è quello di una sequenza lenta da una programmazione funzionale.
Da Wikibooks Programmazione Clojure: Lazy Fibonacci ci sono un certo numero di sequenze pigre per il calcolo della sequenza di Fibonacci . Un esempio:
(def fib-seq
((fn rfib [a b]
(lazy-seq (cons a (rfib b (+ a b)))))
0 1))
user> (take 20 fib-seq)
(0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181)
In questo, la sequenza non viene valutata finché non ne viene richiesta una e può continuare a essere interrogata per ottenere il valore successivo nella sequenza.
Si noti che questa è una sequenza e non una matrice.
L'idea di una struttura che nasconde il calcolo dietro di essa non è certamente unica per i linguaggi funzionali puri.
In perl un esempio di un array in cui si chiede $primes[199]
restituendo il 200esimo primo può essere trovato in Math::Prime::TiedArray . Allo stesso modo, in Python, questa domanda di overflow dello stack crea un iterator / generator (non sono un pitone, non sono esattamente sicuro della termonologia) che genererà un flusso infinito di numeri primi.
Si noti che con i numeri primi si assegna ancora memoria in quanto genera i numeri per rendere il setaccio più ottimale. Se richiedi più oggetti di quanti possano essere contenuti nella memoria, riempirai la memoria. Tuttavia, non calcola il valore finché non lo chiedi.
Specificamente per Java, si potrebbe fare ciò che si desidera in clojure e quindi chiamare il codice clojure da Java - sono entrambe lingue jvm. È un'opzione, anche se non la consiglio.
Per Java, iteratore è un'interfaccia per qualcosa che si muove in una direzione. Il punto chiave è che questa è un'interfaccia - puoi implementarla.
Si consideri:
package com.michaelt.se;
import java.util.Iterator;
public class EvenIter implements Iterator<Integer>
{
private int value = 0;
@Override
public boolean hasNext() {
return true;
}
@Override
public Integer next() {
return (value++ * 2);
}
@Override
public void remove() { }
}
e la demo per eseguirlo
package com.michaelt.se;
public class IterDemo
{
public static void main(String[] args)
{
EvenIter evens = new EvenIter();
for(int i = 0; i < 10; i++) {
System.out.println(i + ": " + evens.next());
}
}
}
Questa è una "lista" infinita di numeri che richiede una piccola quantità costante di memoria. L'ho fatto con l'iterabile, potrebbe essere fatto anche con altre interfacce. Le diapositive della presentazione su flussi infiniti fanno da stream.
Il thunk in particolare è una chiusura da richiamare in seguito quando necessario. Le chiusure sono qualcosa che si trova in Java 7.
Ancora, uno può fare cose simili in Java come codice creando un oggetto con un getter che ha un metodo associato che è quindi memoized . L'idea è "sì, calcolerò questo valore quando effettivamente lo vuoi, ma fino a quel momento, resisti a questo."
La domanda della lista infinita di numeri interi interi (che si tratti di numeri naturali, numeri primi, Fibonacci o qualche altra sequenza) può essere implementata pigra in vari modi in Java. Si riduce davvero a ciò che si vuole fare al di là del "dovrebbe essere pigro e non mangiare tutta la memoria come ottengo grandi numeri".