Immutability atau mutability bukanlah konsep yang masuk akal dalam pemrograman fungsional.
Konteks komputasi
Ini adalah pertanyaan yang sangat bagus yang merupakan tindak lanjut yang menarik (bukan duplikat) ke yang lain baru-baru ini: Apa perbedaan antara penugasan, penilaian dan pengikatan nama?
Alih-alih menjawab pernyataan Anda satu per satu, saya mencoba di sini untuk memberi Anda gambaran umum terstruktur tentang apa yang dipertaruhkan.
Ada beberapa masalah yang harus dipertimbangkan untuk menjawab Anda, termasuk:
Apa itu model perhitungan, dan konsep apa yang masuk akal untuk model yang diberikan
Apa arti dari kata-kata yang Anda gunakan, dan bagaimana kata itu tergantung pada konteksnya
Gaya pemrograman fungsional tampaknya konyol karena Anda melihatnya dengan mata programmer yang sangat penting. Tetapi ini adalah paradigma yang berbeda, dan konsep serta persepsi Anda yang imperatif adalah asing, tidak pada tempatnya. Para penyusun tidak memiliki prasangka seperti itu.
Tetapi kesimpulan akhirnya adalah bahwa adalah mungkin untuk menulis program dengan cara fungsional murni, termasuk untuk pembelajaran mesin, pemikiran pemrograman fungsional tidak memiliki konsep menyimpan data. Saya tampaknya tidak setuju pada poin ini dengan jawaban lain.
Dengan harapan beberapa orang akan tertarik meskipun jawaban ini panjang.
Paradigma komputasi
Pertanyaannya adalah tentang pemrograman fungsional (alias pemrograman aplikatif), model komputasi spesifik, yang representatif teoretis dan paling sederhana adalah kalkulus lambda.
Jika Anda tetap pada level teoretis, ada banyak model perhitungan: mesin Turing (TM), mesin RAM dan lainnya , kalkulus lambda, logika kombinatori, teori fungsi rekursif, sistem semi-Thue, dll. Komputasi yang lebih kuat model telah terbukti setara dalam hal apa yang dapat mereka tangani, dan itulah inti dari
tesis Gereja-Turing .
Konsep penting adalah mereduksi model satu sama lain, yang merupakan dasar untuk menetapkan kesetaraan yang mengarah pada tesis Church-Turing. Dilihat dari perspektif pemrogram, mereduksi satu model ke model lain adalah apa yang biasanya disebut sebagai kompiler. Jika Anda menggunakan pemrograman logika sebagai model perhitungan Anda, ini sangat berbeda dengan model yang disediakan oleh PC yang Anda beli di toko, dan kompiler menerjemahkan program yang ditulis dalam bahasa pemrograman logika ke model komputasi yang diwakili oleh PC Anda (cukup banyak komputer RAM).
β
Dalam praktiknya, bahasa pemrograman yang kami gunakan cenderung untuk memadukan konsep-konsep dari asal-usul teoretis yang berbeda, mencoba melakukannya sehingga bagian-bagian tertentu dari suatu program dapat memperoleh manfaat dari sifat-sifat beberapa model yang sesuai. Demikian pula, orang yang membangun sistem dapat memilih bahasa yang berbeda untuk komponen yang berbeda, untuk menyesuaikan bahasa dengan tugas yang ada.
Karenanya, Anda jarang melihat paradigma pemrograman dalam keadaan murni dalam bahasa pemrograman. Bahasa pemrograman masih diklasifikasikan menurut paradigma dominan, tetapi sifat-sifat bahasa dapat dipengaruhi ketika konsep dari paradigma lain terlibat, sering mengaburkan perbedaan dan masalah konseptual.
Biasanya, bahasa seperti Haskell dan ML atau CAML dianggap fungsional, tetapi mereka dapat memungkinkan untuk perilaku imperatif ... Lain mengapa orang berbicara tentang " subset murni fungsional "?
Maka orang dapat mengklaim itu, Anda dapat melakukan ini atau itu dalam bahasa pemrograman fungsional saya, tetapi itu tidak benar-benar menjawab pertanyaan tentang pemrograman fungsional ketika itu bergantung pada apa yang dapat dianggap ekstra fungsional.
Jawabannya harus lebih tepat terkait dengan paradigma tertentu, tanpa tambahan.
Apa itu variabel?
Masalah lain adalah penggunaan terminologi. Dalam matematika, variabel adalah entitas yang mewakili nilai yang tidak ditentukan dalam beberapa domain. Ini digunakan untuk berbagai keperluan. Digunakan dalam suatu persamaan, itu bisa berdiri untuk nilai apa pun sehingga persamaan diverifikasi. Visi ini digunakan dalam pemrograman logika dengan nama " variabel logis ", mungkin karena variabel nama sudah memiliki arti lain ketika pemrograman logika dikembangkan.
Dalam pemrograman imperatif tradisional, variabel dipahami sebagai semacam wadah (atau lokasi memori) yang dapat menghafal representasi nilai, dan mungkin mendapatkan nilai saat ini digantikan oleh yang lain).
Dalam pemrograman fungsional, variabel memiliki tujuan yang sama dengan matematika dalam sebagai tempat-penampung untuk beberapa nilai, belum disediakan. Dalam pemrograman imperatif tradisional peran ini sebenarnya dimainkan oleh konstan (jangan dikacaukan dengan literal yang ditentukan nilai yang dinyatakan dengan notasi khusus untuk domain nilai-nilai itu, seperti 123, true, ["abdcz", 3.14]).
Variabel apa pun, serta konstan, dapat diwakili oleh pengidentifikasi.
Variabel imperatif dapat mengubah nilainya dan itu adalah dasar untuk mutabilitas. Variabel fungsional tidak bisa.
Bahasa pemrograman biasanya memungkinkan untuk entitas yang lebih besar dibangun dari yang lebih kecil dalam bahasa tersebut.
Bahasa imperatif memungkinkan konstruksi semacam itu untuk memasukkan variabel dan itulah yang memberi Anda data yang bisa berubah.
Cara membaca program
Suatu program pada dasarnya deskripsi abstrak dari algoritma Anda adalah beberapa bahasa, apakah desain pragmatis, atau bahasa yang secara paradigmatik murni.
Pada prinsipnya, Anda dapat mengambil setiap pernyataan untuk apa yang seharusnya dimaksudkan secara abstrak. Kemudian kompiler akan menerjemahkannya ke bentuk yang tepat untuk dieksekusi oleh komputer, tetapi itu bukan masalah Anda dalam perkiraan pertama.
Tentu saja, kenyataannya sedikit lebih keras, dan sering kali baik untuk mengetahui apa yang terjadi sehingga untuk menghindari struktur yang tidak akan dikompilasi oleh kompiler untuk eksekusi yang efisien. Tapi itu sudah optimasi ... compiler mana yang bisa sangat baik, seringkali lebih baik daripada programmer.
Pemrograman fungsional dan mutabilitas
Mutabilitas didasarkan pada keberadaan variabel imperatif yang dapat berisi nilai-nilai, untuk diubah oleh penugasan. Karena ini tidak ada dalam pemrograman fungsional, semuanya dapat dilihat sebagai tidak berubah.
Pemrograman fungsional berurusan secara eksklusif dengan nilai-nilai.
Empat pernyataan pertama Anda tentang kekekalan sebagian besar benar, tetapi jelaskan dengan pandangan imperatif sesuatu yang tidak penting. Ini agak seperti menggambarkan dengan warna di dunia di mana setiap orang buta. Anda menggunakan konsep yang asing dengan pemrograman fungsional.
Anda hanya memiliki nilai murni, dan array bilangan bulat adalah nilai murni. Untuk mendapatkan array lain yang berbeda hanya dalam satu elemen, Anda harus menggunakan nilai array yang berbeda. Mengubah elemen hanyalah sebuah konsep yang tidak ada dalam konteks ini. Anda mungkin memiliki fungsi yang memiliki array dan beberapa indeks sebagai argumen, dan mengembalikan hasil yang merupakan array yang hampir sama yang hanya berbeda di mana ditunjukkan oleh indeks. Tetapi ini masih merupakan nilai array independen. Bagaimana nilai-nilai ini diwakili bukanlah masalah Anda. Mungkin mereka "berbagi" banyak dalam terjemahan imperatif untuk komputer ... tapi itu adalah pekerjaan kompiler ... dan Anda bahkan tidak ingin tahu untuk jenis arsitektur mesin apa yang dikompilasi.
Anda tidak menyalin nilai (itu tidak masuk akal, itu adalah konsep yang asing). Anda cukup menggunakan nilai yang ada di domain yang telah Anda tetapkan dalam program Anda. Entah Anda menggambarkannya (sebagai literal) atau merupakan hasil penerapan fungsi ke beberapa nilai lainnya. Anda dapat memberi mereka nama (sehingga mendefinisikan konstanta) untuk memastikan nilai yang sama digunakan di tempat yang berbeda dalam program. Perhatikan bahwa aplikasi fungsi tidak harus dianggap sebagai perhitungan tetapi sebagai hasil aplikasi ke argumen yang diberikan. Menulis 5+2
atau menulis sama 7
jumlahnya. Yang konsisten dengan paragraf sebelumnya.
Tidak ada variabel imperatif. Tidak ada tugas yang memungkinkan. Anda dapat mengikat nama hanya ke nilai (untuk membentuk konstanta), tidak seperti bahasa imperatif di mana Anda dapat mengikat nama ke variabel yang dapat ditentukan.
Apakah itu memiliki biaya dalam kompleksitas sama sekali tidak jelas. Untuk satu hal, Anda merujuk pada kompleksitas menyangkut paradigma imperatif. Ini tidak didefinisikan seperti itu untuk pemrograman fungsional, kecuali jika Anda memilih untuk membaca program fungsional Anda sebagai keharusan, yang bukan maksud dari perancang. Memang pandangan fungsional dimaksudkan untuk membuat Anda tidak khawatir tentang masalah seperti itu dan berkonsentrasi pada apa yang sedang dihitung. Ini agak mirip spesifikasi versus implementasi.
Kompiler harus menjaga implementasi, dan harus cukup pintar untuk menyesuaikan apa yang harus dilakukan dengan perangkat keras yang akan melakukannya, apa pun itu.
Saya tidak mengatakan programmer tidak pernah khawatir tentang itu. Saya juga tidak mengatakan bahwa bahasa pemrograman dan teknologi kompiler sama matangnya seperti yang kita harapkan.
Menjawab pertanyaan
Anda tidak mengubah nilai yang ada (konsep alien), tetapi menghitung nilai baru yang berbeda di mana diinginkan, mungkin dengan memiliki satu elemen tambahan itu adalah daftar.
Program bisa mendapatkan data baru. Intinya adalah bagaimana Anda mengekspresikannya dalam bahasa. Misalnya, Anda dapat mempertimbangkan bahwa program ini bekerja dengan satu nilai spesifik, mungkin dalam ukuran tidak terbatas, yang disebut aliran input. Ini adalah nilai yang seharusnya duduk di sana (apakah sudah diketahui sepenuhnya atau tidak bukan masalah Anda). Kemudian Anda memiliki fungsi yang mengembalikan pasangan yang terdiri dari elemen pertama dari aliran, dan sisanya dari aliran.
Anda dapat menggunakannya untuk membangun jaringan komponen komunikasi dengan cara yang murni aplikatif (coroutine)
Pembelajaran mesin hanyalah masalah lain ketika Anda harus mengumpulkan data dan mengubah nilai. Dalam pemrograman fungsional Anda tidak melakukan itu: Anda hanya menghitung nilai-nilai baru yang berbeda sesuai dengan data pelatihan. Mesin yang dihasilkan akan bekerja juga. Yang Anda khawatirkan adalah efisiensi waktu dan ruang komputasi. Tetapi, sekali lagi, itu adalah masalah yang berbeda, yang idealnya harus ditangani oleh kompiler.
Komentar akhir
Sangat jelas, dari komentar atau jawaban lain, bahwa bahasa pemrograman fungsional praktis tidak murni fungsional. Itu adalah refleksi dari fakta bahwa teknologi kami masih harus ditingkatkan, terutama dalam hal kompilasi.
Apakah mungkin menulis dengan gaya aplikatif murni? Jawabannya sudah diketahui sekitar 40 tahun dan itu adalah "ya". Tujuan semantik denotasional seperti yang muncul pada tahun 1970-an adalah untuk menerjemahkan (mengkompilasi) bahasa ke dalam gaya yang murni fungsional, dianggap lebih dipahami secara matematis dan dengan demikian dianggap sebagai pendanaan yang lebih baik untuk mendefinisikan semantik program.
Aspek yang menarik adalah bahwa struktur pemrograman imperatif, termasuk variabel, dapat diterjemahkan ke dalam gaya fungsional dengan memperkenalkan domain nilai yang sesuai, seperti penyimpanan data. Dan meskipun gaya fungsional, secara mengejutkan tetap mirip dengan kode kompiler yang sebenarnya ditulis dalam gaya imperatif.