Meskipun kadang-kadang dinyatakan seperti itu, pemrograman fungsional functional tidak mencegah perhitungan stateful. Apa yang dilakukannya adalah memaksa programmer untuk membuat negara eksplisit.
Sebagai contoh, mari kita ambil struktur dasar dari beberapa program menggunakan antrian imperatif (dalam beberapa bahasa):
q := Queue.new();
while (true) {
if (Queue.is_empty(q)) {
Queue.add(q, producer());
} else {
consumer(Queue.take(q));
}
}
Struktur yang sesuai dengan struktur data antrian fungsional (masih dalam bahasa imperatif, sehingga untuk mengatasi satu perbedaan pada suatu waktu) akan terlihat seperti ini:
q := Queue.empty;
while (true) {
if (q = Queue.empty) {
q := Queue.add(q, producer());
} else {
(tail, element) := Queue.take(q);
consumer(element);
q := tail;
}
}
Karena antrian sekarang tidak berubah, objek itu sendiri tidak berubah. Dalam pseudo-code ini, q
itu sendiri adalah variabel; tugas q := Queue.add(…)
dan q := tail
membuatnya menunjuk ke objek yang berbeda. Antarmuka fungsi antrian telah berubah: masing-masing harus mengembalikan objek antrian baru yang dihasilkan dari operasi.
Dalam bahasa murni fungsional, yaitu dalam bahasa tanpa efek samping, Anda harus membuat semua status eksplisit. Karena produsen dan konsumen mungkin melakukan sesuatu, negara mereka juga harus berada di antarmuka penelepon mereka di sini.
main_loop(q, other_state) {
if (q = Queue.empty) {
let (new_state, element) = producer(other_state);
main_loop(Queue.add(q, element), new_state);
} else {
let (tail, element) = Queue.take(q);
let new_state = consumer(other_state, element);
main_loop(tail, new_state);
}
}
main_loop(Queue.empty, initial_state)
Perhatikan bagaimana sekarang setiap bagian dari negara dikelola secara eksplisit. Fungsi manipulasi antrian mengambil antrian sebagai input dan menghasilkan antrian baru sebagai output. Produser dan konsumen melewati negara mereka juga.
Pemrograman konkuren tidak cocok dengan baik di dalam pemrograman fungsional, tapi itu sangat cocok di sekitar pemrograman fungsional. Idenya adalah untuk menjalankan sekelompok node komputasi yang terpisah dan membiarkan mereka bertukar pesan. Setiap node menjalankan program fungsional, dan keadaannya berubah saat ia mengirim dan menerima pesan.
Melanjutkan contoh, karena ada satu antrian, dikelola oleh satu simpul tertentu. Konsumen mengirim pesan kepada simpul itu untuk mendapatkan elemen. Produsen mengirim pesan ke simpul itu untuk menambahkan elemen.
main_loop(q) =
consumer->consume(q->take()) || q->add(producer->produce());
main_loop(q)
Bahasa "industrialisasi" yang mendapat konkurensi benar³ adalah Erlang . Mempelajari Erlang jelas merupakan jalan menuju pencerahan⁴ tentang pemrograman bersamaan.
Semua orang beralih ke bahasa bebas efek samping sekarang!
¹ Istilah ini memiliki beberapa arti; di sini saya pikir Anda menggunakannya berarti pemrograman tanpa efek samping, dan itulah artinya saya juga menggunakan.
² Pemrograman dengan status implisit adalah pemrograman imperatif ; orientasi objek adalah perhatian yang sepenuhnya ortogonal.
³ Peradangan, saya tahu, tetapi saya bersungguh-sungguh. Utas dengan memori bersama adalah bahasa rakitan pemrograman bersamaan. Pesan lewat jauh lebih mudah untuk dipahami, dan kurangnya efek samping benar-benar bersinar segera setelah Anda memperkenalkan konkurensi.
⁴ Dan ini datang dari seseorang yang bukan penggemar Erlang, tetapi karena alasan lain.