Pemanggilan Ekor yang Sesuai (Proper Tail Calls)
Pemanggilan Ekor yang Sesuai (Proper Tail Calls) - LEBIH JAUH DENGAN FUNGSI
===
6.3 Pemanggilan Ekor yang Sesuai (Proper Tail Calls)
Fitur lain yang menarik dari fungsi pada Lua adalah mereka dapat memanggil ekornya sendiri.(beberapa penulis menggunakan istilah proper tail recursion, meskipun konsepnya tidak melibatkan rekursi secara langsung.)
Sebuah Tail Call terjadi ketika sebuah fungsi memanggil fungsi yang lain sebagai aksi terakhir,jadi tidak ada lagi yang dikerjakan. Untuk contoh,seperi kode dibawah ini,pemanggilan g adalah tail call:
function f (x) return g(x) end
Setelah f memanggil g,tidak ada lagi yang dikerjakan. Dalam beberapa keadaan,program tidak butuh untuk mengembalikan fungsi pemanggilan ketika fungsi pemanggilan berakhir. Oleh karena itu,setelah tail call,program tidak butuh menjaga informasi tentang pemanggilan fungsi di stack. Beberapa implementasi bahasa seperti interpreter Lua,mengambil keuntungan dari sini dan nyatanya tidak menggunakan stack tambahan ketika memanggil tail call. Kita katakan implementasi itu mendukung proper tail calls.
Karena sebuah proper tail calls tidak menggunakan ruang stack,maka tidak ada batasan angka untuk memanggil tail calls yang berkaitan yang dibuat oleh program. Sebagai contoh,kita akan memanggil fungsi dibawah dengan beberapa angka sebagai argumen. Ini tidak pernah menyebabkan stack yang overflow:
function foo (n) if n > 0 then return foo(n - 1) end end
Sebuah nilai yang sulit dipisahkan ketika kita menggunakan proper tail calls adalah apa yang disebut tail call. Beberapa contoh yang salah adalah memanggil fungsi yang tidak akan dikerjakan setelah fungsi dipanggil. Sebagai contoh,kode dibawah ini,panggilan terhadap g bukan tail call:
function f (x) g(x) return
end
Masalahnya dalam contoh ini adalah,setelah pemanggilan g,hasil dari f masih belum dihapus sama sekali. Sama dengan pemanggilan yang salah dibawah ini:
return g(x) + 1 -- must do the addition return x or g(x) -- must adjust to 1 result return (g(x)) -- must adjust to 1 result
Dalam Lua,hanya sebuah pemanggilan dalam format return g(…) yang disebut tail call. Tetapi,keduanya baik g dan argumen dapat berupa ekspresi yang kompleks,karena Lua mengevaluasi mereka sebelum dipanggil. Sebagai contoh pemanggilan dibawah ini adalah tail call:
return x[i].foo(x[j] + a*b, i + j)
Seperti yang telah disebutkan sebelumnya,sebuah tail call adalah semacam goto. Sebagai contoh,kegunaan aplikasi proper tail calls pada Lua adalah untuk pemrograman bagian mesin. Beberapa aplikasi dapat digambarkan setiap langkahnya oleh sebuah fungsi. Untuk merubah masing-masing bagian kita akan memanggil fungsi spesifik. Sebagai contoh,kita buat contoh permainan sederhana untuk mencari jalan. Permainan ini memiliki beberapa ruangan yang terdiri dari 4 pintu yaitu utara,selatan,timur dan barat. Pada setiap langkah,pengguna memasukkan pergerakan arah. Jika ada sebuah pintu yang sesuai dengan arah tersebut,pengguna akan masuk kedalam ruangan yang sesuai dengan arah tersebut: Jika tidak,program akan mencetak peringatan. Tujuan dari permainan ini adalah berjalan dari ruangan pertama hingga ruangan terakhir.
Permainan ini adalah ciri dari state machine,dimana setiap ruangan adalah sebuah state. Kita dapat mengimplementasikan permainan ini dengan satu fungsi untuk satu ruangan. Kita Permainan ini adalah ciri dari state machine,dimana setiap ruangan adalah sebuah state. Kita dapat mengimplementasikan permainan ini dengan satu fungsi untuk satu ruangan. Kita
function room1 () local move = io.read() if move == "south" then return room3() elseif move == "east" then return room2() else print("invalid move")
return room1() -- stay in the same room end end
function room2 () local move = io.read() if move == "south" then return room4() elseif move == "west" then return room1() else print("invalid move")
return room2()
end end
function room3 () local move = io.read() if move == "north" then return room1() elseif move == "east" then return room4() else print("invalid move")
return room3()
end end
function room4 () print("congratulations!") end
Kita mulai permainan ini dengan memanggil ruangan pertama:
room1()
Tanpa proper tail calls , setiap pergerakan pemain akan membuat sebuah stack level baru. Setelah beberapa pergerakan,stack akan mengalami overflow. Dengan proper tail calls, tidak ada batasan bagi pemain untuk berapa kali melakukan pergerakan,karena setiap pergerakan biasanya menampilkan sebuah penunjuk ke fungsi lain bukan pemanggilan konvensional.
Untuk permainan sederhana,kamu boleh menggunakan data-driven program, dimana kamu mendeskripsikan ruangan dan pergerakan dengan tabel,yang merupakan rancangan yang lebih baik dari sebelumnya. Tetapi,jika permainan memiliki keadaan yang berbeda di setiap ruangan, rancangan state machine tidak dapat digunakan.
Latihan
Ketikalah listing kode berikut. Lalu jalankan untuk mendapatkan nilai faktotrial dan Fibonacci dari suatu bilangan Ketikalah listing kode berikut. Lalu jalankan untuk mendapatkan nilai faktotrial dan Fibonacci dari suatu bilangan
function fibonacci(n) if (n==1 or n==2) then return 1 else return fibonacci(n-2) + fibonacci(n-1) end end
function menu() print("===MENU PILIHAN===") print(" 1. FAKTORIAL") print(" 2. FIBONACCI") print(" 3. KELUAR") print(" MASUKKAN PILIHAN ANDA : ") pil = io.read("*number")
if pil==1 then print() print("===MENU FAKTORIAL===") print("Input Bilangan : ") n = io.read("*number") io.write(n,"! : ") print(factorial(n))
print() print(menu()) else if pil==2 then
print() print("===MENU FIBONACCI===") print("Suku Bilangan Ke : ") n = io.read("*number") io.write("Nilai Suku ke-",n," adalah ") print(fibonacci(n))
print() print(menu()) else if pil==3 then
print("Terima Kasih...") else print("Masukkan Pilihan 1 sampai 3") print() print(menu())
end end end end print(menu())