Coroutines sebagai iterator

9.3 Coroutines sebagai iterator

Kita dapat melihat loop iterator sebagai sebuah contoh spesifik bentuk producer-consumer sebuah iterator memproduksi barang untuk dipakai oleh badan loop. Oleh karena itu,ini terlihat aneh menggunakan coroutines untuk menulis iterator. Nyatanya,coroutine memberikan sebuah alat yang kuat untuk pekerjaan ini. Kembali,kunci dari fitur ini adalah kemampuan merubah hubungan antara pemanggil dan terpanggil. Dengan fitur ini,kita dapat menulis iterator tanpa masalah dengan bagaimana menjaga bagian antara pemanggilan successive ke iterator.

Untuk mengilustrasikan macam kegunaannya,tuliskan sebuah iterator untuk merubah seluruh permutasi pada array yang diberikan. Ini bukan pekerjaan mudah untuk menulis secara langsung sebuah iterator,tetapi ini tidak sulit untuk menulis sebuah fungsi rekursif yang menghasilkan seluruh permutasi. Idenya simple,letakkan setiap elemen array di posisi terakhir,tukar dan hasilkan seluruh permutasi dari masing-masing elemen secara rekursif. Kode seperti dibawah ini:

function permgen (a, n) if n == 0 then

printResult(a)

else

for i=1,n do

-- put i-th element as the last one a[n], a[i] = a[i], a[n]

-- generate all permutations of the other elements permgen(a, n - 1)

-- restore i-th element a[n], a[i] = a[i], a[n]

end

end end

Untuk melihat cara kerjanya,kita seharusnya mendefinisikan sebuah fungsi printResult dan memanggil permgen dengan beberapa argumen:

function printResult (a) for i,v in ipairs(a) do

io.write(v, " ")

end io.write("\n")

end

permgen ({1,2,3,4}, 4)

Setelah generator yang kita punya sudah siap. Generator akan mengerjakan perubahan ke sebuah iterator secara otomatis. Pertama,kita merubah printResult ke yield:

function permgen (a, n) if n == 0 then

coroutine.yield(a)

else

Kemudian kita definiskan sebuah induk yang mengatur generator untuk berjalan dalam coroutine,dan kemudian membuat fungsi iterator. Iterator sederhana memanggil coroutine untuk menghasilkan permutasi selanjutnya.

function perm (a) local n = table.getn(a) local co = coroutine.create(function () permgen(a, n)

end) return function () -- iterator

local code, res = coroutine.resume(co) return res

end end

Dengan mesin-mesin ditempat,ini biasa untuk mengiterasi semua permutasi dalam array dengan statemen for:

for p in perm{"a", "b", "c"} do printResult(p) end --> b c a --> c b a --> c a b --> a c b --> b a c --> a b c

Fungsi perm menggunakan bentuk biasa dalam Lua,yang mana membungkus panggilan ke resume dengan coroutine yang saling berhubungan kedalam sebuah fungsi. Bentuk ini,biasanya Lua berikan dalam fungsi special: coroutine.wrap. Seperti create,wrap membuat sebuah coroutine baru. Tidak seperti create,wrap tidak mengembalikan coroutine sendiri: Ia mengembalikan sebuah fungsi,yang ketika dipanggil,melanjutkan coroutine. Tidak seperti resume asli,fungsi ini tidak mengembalikan sebuah kode error sebagai hasil pertama; memunculkan kesalahan jika terjadi kesalahan menggunakan wrap. Kita dapat menulis perm seperti dibawah ini:

function perm (a) local n = table.getn(a) return coroutine.wrap(function () permgen(a, n) end)

end

Biasanya coroutine.wrap lebih sederhana untuk digunakan dibandingkan dengan coroutine.create. Ini memberikan kita kenyataan apa yang kita butuhkan dari sebuah coroutine: Sebuah fungsi untuk memanggil ini. Tetapi,ini juga kurang fleksibel. Kita tidak bisa memeriksa status dari coroutine yang dibuat dengan wrap. Dan lagi,kita tidak dapat memeriksa kesalahan.