Jika Anda membangun operasi minimum komputer generik dari awal, "Iterasi" diutamakan sebagai blok penyusun dan lebih sedikit sumber daya daripada "rekursi", ergo lebih cepat.
Kami akan membangun hierarki konsep, mulai dari awal dan mendefinisikan di tempat pertama konsep dasar, inti, kemudian membangun konsep tingkat kedua dengan itu, dan seterusnya.
Konsep Pertama: Sel memori, penyimpanan, Status . Untuk melakukan sesuatu, Anda perlu tempat untuk menyimpan nilai hasil akhir dan menengah. Mari kita asumsikan kita memiliki array tak terbatas dari sel "integer", yang disebut Memory , M [0..Infinite].
Instruksi: melakukan sesuatu - mengubah sel, mengubah nilainya. ubah status . Setiap instruksi menarik melakukan transformasi. Instruksi dasar adalah:
a) Atur & pindahkan sel memori
- menyimpan nilai ke dalam memori, misalnya: store 5 m [4]
- salin nilai ke posisi lain: mis .: store m [4] m [8]
b) Logika dan aritmatika
- dan, atau, xor, tidak
- tambahkan, sub, mul, div. mis. tambahkan m [7] m [8]
An Executing Agent : inti dalam CPU modern. "Agen" adalah sesuatu yang dapat menjalankan instruksi. Sebuah Agen juga bisa menjadi orang yang mengikuti algoritma di atas kertas.
Urutan langkah-langkah: urutan instruksi : yaitu: lakukan ini dulu, lakukan ini setelah, dll. Urutan instruksi yang penting. Bahkan satu kalimat ekspresi adalah "urutan instruksi imperatif". Jika Anda memiliki ekspresi dengan "urutan evaluasi" tertentu maka Anda memiliki langkah - langkah . Itu berarti daripada bahkan satu ekspresi yang dikomposisikan memiliki "langkah" dan juga memiliki variabel lokal implisit (sebut saja "hasil"). misalnya:
4 + 3 * 2 - 5
(- (+ (* 3 2) 4 ) 5)
(sub (add (mul 3 2) 4 ) 5)
Ekspresi di atas menyiratkan 3 langkah dengan variabel "hasil" implisit.
// pseudocode
1. result = (mul 3 2)
2. result = (add 4 result)
3. result = (sub result 5)
Jadi bahkan ekspresi infiks, karena Anda memiliki urutan evaluasi tertentu, adalah urutan instruksi yang penting . Ekspresi menyiratkan urutan operasi yang akan dibuat dalam urutan tertentu, dan karena ada langkah - langkah , ada juga variabel perantara "hasil" implisit.
Pointer Instruksi : Jika Anda memiliki urutan langkah-langkah, Anda juga memiliki "pointer instruksi" implisit. Penunjuk instruksi menandai instruksi selanjutnya, dan maju setelah instruksi dibaca tetapi sebelum instruksi dieksekusi.
Dalam pseudo-computing-machine ini, Instruction Pointer adalah bagian dari Memory . (Catatan: Biasanya Instruction Pointer akan menjadi "register khusus" dalam inti CPU, tetapi di sini kami akan menyederhanakan konsep dan menganggap semua data (termasuk register) adalah bagian dari "Memori")
Langsung - Setelah Anda memiliki jumlah langkah yang dipesan dan Instruksi Pointer , Anda dapat menerapkan instruksi " store " untuk mengubah nilai Pointer Instruksi itu sendiri. Kami akan menyebut penggunaan spesifik dari instruksi toko ini dengan nama baru: Jump . Kami menggunakan nama baru karena lebih mudah untuk memikirkannya sebagai konsep baru. Dengan mengubah pointer instruksi, kami menginstruksikan agen untuk "pergi ke langkah x".
Iterasi Infinite : Dengan melompat mundur, sekarang Anda dapat membuat agen "mengulang" sejumlah langkah tertentu. Pada titik ini kita memiliki Iterasi tanpa batas.
1. mov 1000 m[30]
2. sub m[30] 1
3. jmp-to 2 // infinite loop
Bersyarat - Eksekusi instruksi bersyarat. Dengan klausa "kondisional", Anda dapat menjalankan salah satu dari beberapa instruksi berdasarkan kondisi saat ini (yang dapat diatur dengan instruksi sebelumnya).
Iterasi yang Tepat : Sekarang dengan klausa kondisional , kita dapat menghindari loop tak terbatas dari instruksi lompat kembali . Kami sekarang memiliki loop kondisional dan kemudian Iterasi yang tepat
1. mov 1000 m[30]
2. sub m[30] 1
3. (if not-zero) jump 2 // jump only if the previous
// sub instruction did not result in 0
// this loop will be repeated 1000 times
// here we have proper ***iteration***, a conditional loop.
Penamaan : memberi nama ke lokasi memori tertentu yang menyimpan data atau menahan langkah . Ini hanya "kemudahan" untuk dimiliki. Kami tidak menambahkan instruksi baru dengan memiliki kapasitas untuk mendefinisikan "nama" untuk lokasi memori. "Penamaan" bukan instruksi untuk agen, itu hanya kenyamanan bagi kami. Penamaan membuat kode (pada titik ini) lebih mudah dibaca dan lebih mudah diubah.
#define counter m[30] // name a memory location
mov 1000 counter
loop: // name a instruction pointer location
sub counter 1
(if not-zero) jmp-to loop
Subrutin satu tingkat : Misalkan ada serangkaian langkah yang perlu Anda lakukan sesering mungkin. Anda dapat menyimpan langkah-langkah dalam posisi yang disebutkan dalam memori dan kemudian melompat ke posisi itu ketika Anda perlu menjalankannya (panggilan). Pada akhir urutan Anda harus kembali ke titik panggilan untuk melanjutkan eksekusi. Dengan mekanisme ini, Anda membuat instruksi baru (subrutin) dengan menyusun instruksi inti.
Implementasi: (tidak diperlukan konsep baru)
- Simpan Instruction Pointer saat ini dalam posisi memori yang telah ditentukan
- lompat ke subrutin
- di akhir subrutin, Anda mengambil Instruksi Pointer dari lokasi memori yang telah ditentukan, secara efektif melompat kembali ke instruksi berikut dari panggilan asli
Masalah dengan implementasi satu tingkat : Anda tidak dapat memanggil subrutin lain dari subrutin. Jika ya, Anda akan menimpa alamat yang kembali (variabel global), jadi Anda tidak bisa membuat panggilan.
Untuk memiliki Implementasi yang lebih baik untuk subrutin: Anda memerlukan STACK
Stack : Anda mendefinisikan ruang memori untuk berfungsi sebagai "tumpukan", Anda dapat "mendorong" nilai-nilai pada tumpukan, dan juga "pop" nilai "dorongan" terakhir. Untuk mengimplementasikan stack, Anda memerlukan Stack Pointer (mirip dengan Instruction Pointer) yang menunjuk ke "head" sebenarnya dari stack. Ketika Anda "mendorong" suatu nilai, penumpukan tumpukan akan berkurang dan Anda menyimpan nilainya. Ketika Anda "pop", Anda mendapatkan nilai di Stack Pointer yang sebenarnya dan kemudian Stack Pointer bertambah.
Subrutin Sekarang kami memiliki tumpukan, kami dapat menerapkan subrutin yang tepat yang memungkinkan panggilan bersarang . Implementasinya mirip, tetapi alih-alih menyimpan Instruction Pointer dalam posisi memori yang telah ditentukan, kami "mendorong" nilai IP dalam tumpukan . Pada akhir subrutin, kami hanya "pop" nilai dari tumpukan, secara efektif melompat kembali ke instruksi setelah panggilan asli . Implementasi ini, memiliki "tumpukan" memungkinkan memanggil subrutin dari subrutin lain. Dengan implementasi ini kita dapat membuat beberapa level abstraksi ketika mendefinisikan instruksi baru sebagai subrutin, dengan menggunakan instruksi inti atau subrutin lainnya sebagai blok bangunan.
Rekursi : Apa yang terjadi ketika subrutin memanggil dirinya sendiri? Ini disebut "rekursi".
Masalah: Menimpa hasil perantara lokal yang dapat disimpan oleh subrutin dalam memori. Karena Anda memanggil / menggunakan kembali langkah-langkah yang sama, jika hasil antara disimpan di lokasi memori yang telah ditentukan (variabel global) mereka akan ditimpa pada panggilan bersarang.
Solusi: Untuk memungkinkan rekursi, subrutin harus menyimpan hasil antara lokal di stack , oleh karena itu, pada setiap panggilan rekursif (langsung atau tidak langsung) hasil antara disimpan di lokasi memori yang berbeda.
...
Akhirnya, perhatikan bahwa Anda memiliki banyak kesempatan untuk menggunakan rekursi. Anda memiliki Struktur Data Rekursif di mana-mana, Anda sedang melihatnya sekarang: bagian DOM yang mendukung apa yang Anda baca adalah RDS, ekspresi JSON adalah RDS, sistem file hierarkis di komputer Anda adalah RDS, yaitu: Anda memiliki direktori root, yang berisi file dan direktori, setiap direktori yang berisi file dan direktori, setiap direktori yang berisi file dan direktori ...