Saya sedang berpikir tentang bagaimana meyakinkan diri saya bahwa mesin Turing adalah model umum perhitungan. Saya setuju bahwa perlakuan standar tesis Church-Turing dalam beberapa buku teks standar, misalnya Sipser, tidak terlalu lengkap. Berikut ini adalah sketsa bagaimana saya bisa beralih dari mesin Turing ke bahasa pemrograman yang lebih dikenal.
Pertimbangkan bahasa pemrograman dengan if
dan while
pernyataan blok-terstruktur , dengan fungsi dan subrutin yang didefinisikan non-rekursif , dengan variabel acak bernama boolean dan ekspresi boolean umum, dan dengan array boolean tunggal tanpa tape[n]
batas dengan pointer bilangan bulat integer n
yang dapat ditambahkan atau dikurangi, n++
atau n--
. Pointer n
awalnya nol dan array tape
awalnya semua nol. Jadi, bahasa komputer ini bisa seperti C atau Python, tetapi sangat terbatas dalam tipe datanya. Bahkan, mereka sangat terbatas sehingga kita bahkan tidak memiliki cara untuk menggunakan pointer n
dalam ekspresi boolean. Berasumsi bahwatape
hanya infinite ke kanan, kita dapat mendeklarasikan pointer underflow "kesalahan sistem" jika n
pernah negatif. Juga, bahasa kita memiliki exit
pernyataan dengan satu argumen, untuk menghasilkan jawaban boolean.
Kemudian poin pertama adalah bahwa bahasa pemrograman ini adalah bahasa spesifikasi yang baik untuk mesin Turing. Anda dapat dengan mudah melihat bahwa, kecuali untuk larik kaset, kode hanya memiliki banyak kemungkinan keadaan: Keadaan semua variabel yang dideklarasikan, dan garis eksekusi saat ini, dan tumpukan subrutinnya. Yang terakhir hanya memiliki jumlah negara terbatas karena fungsi rekursif tidak diperbolehkan. Anda dapat membayangkan "kompiler" yang menciptakan mesin Turing "aktual" dari kode jenis ini, tetapi detailnya tidak penting. Intinya adalah bahwa kita memiliki bahasa pemrograman dengan sintaks yang cukup bagus, tetapi tipe data yang sangat primitif.
Sisa konstruksi adalah untuk mengonversikan ini ke bahasa pemrograman yang lebih layak huni dengan daftar fungsi perpustakaan yang terbatas dan tahap-tahap prakompilasi. Kami dapat melanjutkan sebagai berikut:
Dengan precompiler, kita dapat memperluas tipe data boolean ke alfabet simbol yang lebih besar tetapi terbatas seperti ASCII. Kita dapat mengasumsikan bahwa tape
mengambil nilai dalam alfabet yang lebih besar ini. Kita dapat meninggalkan marker di awal kaset untuk mencegah pointer underflow, dan marker bergerak di ujung tape untuk mencegah TM dari skating hingga tak terbatas pada tape secara tidak sengaja. Kami dapat menerapkan operasi biner acak antara simbol, dan konversi ke boolean untuk if
dan while
pernyataan. (Sebenarnya if
dapat diimplementasikan dengan while
baik, jika itu tidak tersedia.)
kksayasayak
Kami menetapkan satu kaset sebagai "memori" yang dihargai simbol dan yang lainnya sebagai "register" atau "variabel" yang dinilai tidak bertanda. Kami menyimpan bilangan bulat dalam biner little-endian dengan marker termination. Kami pertama-tama mengimplementasikan salinan register dan pengurangan biner dari register. Menggabungkannya dengan peningkatan dan penurunan pointer memori, kita dapat mengimplementasikan pencarian akses acak dari memori simbol. Kita juga dapat menulis fungsi untuk menghitung penambahan biner dan perkalian bilangan bulat. Tidak sulit untuk menulis fungsi penambahan biner dengan operasi bitwise, dan fungsi untuk mengalikan 2 dengan shift kiri. (Atau benar-benar bergeser, karena ini adalah little-endian.) Dengan primitif ini, kita dapat menulis fungsi untuk melipatgandakan dua register menggunakan algoritma multiplikasi panjang.
Kita dapat mengatur ulang rekaman memori dari lambang simbol satu dimensi ke lambang simbol symbol[n]
dua dimensi symbol[x,y]
menggunakan rumus n = (x+y)*(x+y) + y
. Kita sekarang dapat menggunakan setiap baris memori untuk mengekspresikan integer yang tidak ditandai dalam biner dengan simbol terminasi, untuk mendapatkan memori satu dimensi, akses acak, bernilai integer memory[x]
. Kita dapat mengimplementasikan pembacaan dari memori ke register integer, dan menulis dari register ke memori. Banyak fitur sekarang dapat diimplementasikan dengan fungsi: Aritmatika titik yang ditandatangani dan mengambang, string simbol, dll.
Hanya satu fasilitas dasar lagi yang benar-benar membutuhkan precompiler, yaitu fungsi rekursif. Ini dapat dilakukan dengan teknik yang banyak digunakan untuk mengimplementasikan bahasa yang ditafsirkan. Kami menetapkan setiap string tingkat tinggi, fungsi rekursif nama, dan kami mengatur kode tingkat rendah menjadi satu while
loop besar yang mempertahankan tumpukan panggilan dengan parameter biasa: titik panggilan, fungsi yang dipanggil, dan daftar argumen.
Pada titik ini, konstruksi memiliki fitur yang cukup dari bahasa pemrograman tingkat tinggi yang fungsionalitas lebih lanjut lebih merupakan topik bahasa pemrograman dan kompiler daripada teori CS. Juga sudah mudah untuk menulis simulator mesin Turing dalam bahasa yang dikembangkan ini. Memang tidak mudah, tetapi tentu standar, untuk menulis self-compiler untuk bahasa tersebut. Tentu saja Anda memerlukan kompiler luar untuk membuat TM luar dari kode dalam bahasa seperti C atau Python, tetapi itu bisa dilakukan dalam bahasa komputer apa pun.
Perhatikan bahwa implementasi sketsa ini tidak hanya mendukung tesis Church-Turing ahli logika untuk kelas fungsi rekursif, tetapi juga tesis Church-Turing diperpanjang (yaitu, polinomial) yang berlaku untuk perhitungan deterministik. Dengan kata lain, ia memiliki overhead polinomial. Bahkan, jika kita diberi mesin RAM atau (favorit pribadi saya) pohon-tape TM, ini dapat direduksi menjadi overhead polylogarithmic untuk perhitungan serial dengan memori RAM.