Robitex's Blog

Ideas in the web

Iteratori in Lua


Costruzione di un iteratore in Lua

La costruzione di un iteratore in Lua si basa sulla creazione di una funzione che restituisce uno alla volta gli elementi dell’insieme nella sequenza desiderata. Una volta costruito l’iteratore, questo potrà essere impiegato in un ciclo foreach — che in Lua viene chiamato generic for — in modo molto efficiente.
Se per esempio si volesse iterare la collezione dei numeri pari compresi nell’intervallo da 1 a 10, avendo a disposizione l’apposito iteratore evenNum(first, last) che definiremo in seguito, potrei scrivere semplicemente:

for n in evenNum(1,10) do
   print(n)
end

ottenendo in console:

2
4
6
8
10

Numeri pari

Per definire questo iteratore dobbiamo creare una funzione che restituisce a sua volta una funzione in grado di generare la sequenza dei numeri pari. L’iterazione termina quando giunti all’ultimo elemento, la funzione restituirà il valore nullo ‘nil’, cosa che succede in automatico senza dover esplicitare un’istruzione di return.
Per prima cosa si calcola il numero pari successivo al numero di partenza dell’intervallo. Lo faremo usando la funzione math.ceil() che fornisce il numero arrotondato al primo intero superiore dell’argomento. Poi viene restituita la funzione in sintassi anonima che prima incrementa di 2 il numero pari precedente — ed ecco perché inizialmente viene sottratta la stessa quantità all’indice — e, se questo è inferiore all’estremo superiore dell’intervallo, verrà restituito l’indice corrente, il numero pari della sequenza:

-- iteratore dei numeri pari compresi
-- nell'intervallo [i, e]
function evenNum(i, e)
   -- primo numero pari della sequenza
   i = 2*math.ceil(i/2) - 2
   return function ()
             i = i + 2
             if i<=e then
                return i
             end
          end
end

Tecnicamente il sistema funziona perché ogni volta che viene chiamata una funzione, Lua crea le necessarie variabili in una nuova area di memoria, così che la funzione anonima possa lavorare correttamente. Ulteriori particolari possono essere reperiti nel libro ‘Programming in Lua‘, cosa consigliabile se si devono costruire iteratori in ambienti di produzione.

Naturalmente, l’implementazione data di evenNum() è solo una delle possibili soluzioni, e non è detto che non debbano essere considerate situazioni particolari come quella in cui si passa all’iteratore un solo numero o addirittura nessun argomento.

Stateless iterator

Una seconda versione del generatore di numeri pari può essere un buon esempio di un iteratore in Lua che non necessita di un area di memoria — chiamata closure — per un risultato ancora più efficiente.
Per capire come ciò sia possibile dobbiamo conoscere come funziona il ‘generic for’ in Lua; dopo la parola chiave ‘in’ esso si aspetta tre parametri: la funzione dell’iteratore da chiamare ad ogni ciclo, una variabile che rappresenta lo stato invariante, e la variabile di controllo.
Nel seguente codice la funzione evenNum() provvede a restituire i tre parametri necessari: la funzione nextEven() come iteratore, lo stato invariante che per noi è il numero a cui la sequenza dovrà fermarsi, e la variabile di controllo che è proprio il numero della sequenza dei numeri pari, e con ciò abbiamo realizzato un stateless iterator in Lua.
La funzione iteratrice nextEven() verrà chiamata ad ogni ciclo con nell’ordine lo stato invariante e la variabile di controllo, pertanto fate attenzione, dovete mettere in questo stesso ordine gli argomenti nella definizione.

-- even numbers stateless iterator
local function nextEven(last, i)
   i = i + 2
   if i<=last then
      return i
   end
end

local function evenNum(a, b)
   a = 2*math.ceil(a/2)
   return nextEven, b, a-2
end

-- example of generic for
for n in evenNum(10,20) do
print(n)
end

Lua non finisce mai di stupire…
Alla prossima!

Una risposta a “Iteratori in Lua

  1. Pingback:Iterare su SQLite con Lua « Robitex's Blog

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: