Dalam seri artikel ini, Anda akan menjadi terbiasa dengan prinsip-prinsip dasar pemrograman fungsional dan memahami apa artinya "berpikir secara fungsional" dan bagaimana pendekatan ini berbeda dari pemrograman berorientasi objek atau imperatif.

Sekarang Anda telah melihat beberapa alasan mengapa Anda harus menggunakan F #, dalam artikel “ Menyelam ke F #. A Guide for C # Developers ”, mundur selangkah dan bahas dasar-dasar pemrograman fungsional. Apa arti "pemrograman fungsional" sebenarnya, dan bagaimana pendekatan ini berbeda dari pemrograman berorientasi objek atau imperatif?
Change of mindset (Intro)
Penting untuk dipahami bahwa pemrograman fungsional bukan hanya gaya pemrograman yang terpisah. Ini adalah cara berpikir yang sangat berbeda dalam pemrograman, yang berbeda dari pendekatan "tradisional" sama pentingnya dengan OOP saat ini (dalam gaya Smalltalk) berbeda dari bahasa imperatif tradisional seperti C.
F # memungkinkan Anda untuk menggunakan gaya pengkodean non-fungsional, dan ini menggoda programmer untuk mempertahankan kebiasaannya yang sudah ada. Anda dapat memprogram dalam F # seperti yang biasa Anda lakukan, tanpa mengubah pandangan dunia secara radikal, dan bahkan tanpa mengetahui apa yang Anda lewatkan. Namun, untuk mendapatkan hasil maksimal dari F #, dan juga untuk mempelajari cara memprogram dengan percaya diri dalam gaya fungsional secara umum, sangat penting untuk belajar berpikir secara fungsional dan bukan keharusan.
Tujuan dari seri artikel ini adalah untuk membantu pembaca memahami latar belakang pemrograman fungsional dan mengubah cara berpikirnya.
Ini akan menjadi seri yang cukup abstrak, walaupun saya akan menggunakan banyak contoh kode pendek untuk menunjukkan beberapa poin. Kami akan membahas topik-topik berikut:
- Fungsi matematika . Artikel pertama memperkenalkan konsep matematika yang mendasari bahasa fungsional dan manfaat yang dibawa oleh pendekatan ini.
- Fungsi dan Nilai . Berikut ini memperkenalkan fungsi dan nilai, menjelaskan bagaimana "nilai" berbeda dari variabel, dan apa persamaan antara fungsi dan nilai sederhana.
- Jenis . Kemudian kita beralih ke tipe utama yang berfungsi dengan fungsi: tipe primitif seperti string dan int, tipe unit, tipe fungsional, dan tipe generik.
- Berfungsi dengan beberapa parameter . Saya selanjutnya akan menjelaskan konsep "currying" dan "aplikasi parsial". Di tempat ini, otak seseorang akan terluka, terutama jika otak ini hanya memiliki masa lalu yang sangat penting.
- Definisi fungsi . Kemudian beberapa posting akan dikhususkan untuk berbagai cara mendefinisikan dan menggabungkan fungsi.
- Tanda tangan fungsi . Berikut ini adalah posting penting tentang nilai kritis dari tanda tangan fungsi, apa artinya, dan bagaimana menggunakan tanda tangan untuk memahami isi fungsi.
- Organisasi fungsi . Ketika menjadi jelas bagaimana cara membuat fungsi, muncul pertanyaan: bagaimana Anda bisa mengaturnya agar dapat diakses oleh sisa kode?
Fungsi matematika
Pemrograman fungsional terinspirasi oleh matematika. Fungsi matematika memiliki sejumlah fitur yang sangat bagus yang coba diterapkan oleh bahasa fungsional.
Mari kita mulai dengan fungsi matematika yang menambahkan 1 ke angka.
Add1(x) = x+1
Apa arti ungkapan ini? Ini terlihat sangat sederhana. Ini berarti ada operasi seperti itu yang mengambil nomor dan menambahkan 1 untuk itu.
Tambahkan beberapa terminologi:
- Himpunan nilai fungsi input yang valid disebut domain (lingkup). Dalam contoh ini, itu bisa menjadi angka nyata, tetapi kita akan membuat hidup lebih sederhana dan membatasi diri kita di sini ke angka keseluruhan.
- Himpunan hasil yang mungkin dari fungsi (rentang nilai) disebut rentang (secara teknis, gambar codomain ). Dalam hal ini, ada juga banyak bilangan bulat.
- Suatu fungsi disebut pemetaan (dalam peta asli) dari domain ke jangkauan. (Yaitu, dari ruang lingkup ke ruang lingkup.)

Beginilah definisi ini akan terlihat dalam F #.
let add1 x = x + 1
Jika Anda memasukkannya dalam F # Interactive (jangan lupa tentang koma ganda), maka Anda dapat melihat hasilnya ("tanda tangan" dari fungsi):
val add1 : int -> int
Pertimbangkan kesimpulannya secara terperinci:
- Arti umum adalah bahwa fungsi
add1
membandingkan bilangan bulat (dari domain definisi) dengan bilangan bulat (dari rentang nilai). - "
add1
" didefinisikan sebagai "val", kependekan dari "value". Hm? apa artinya Kami akan membahas maknanya sedikit kemudian. - Notasi panah "->" digunakan untuk menampilkan domain dan jangkauan. Dalam hal ini, domain bertipe 'int', seperti rentang.
Perhatikan bahwa tipe itu tidak ditentukan secara eksplisit, tetapi kompiler F # memutuskan bahwa fungsi tersebut bekerja dengan int. (Bisakah ini diubah? Ya, dan segera kita akan melihatnya).
Properti utama dari fungsi matematika
Fungsi matematika memiliki sejumlah properti yang membedakannya sangat banyak dari fungsi yang digunakan dalam pemrograman prosedural.
- Suatu fungsi selalu memiliki hasil yang sama untuk nilai input yang sama.
- Fungsi ini tidak memiliki efek samping.
Properti ini menyediakan sejumlah keunggulan penting yang coba disadari oleh bahasa pemrograman fungsional sebanyak mungkin dalam desainnya. Kami akan mempertimbangkan masing-masing dari mereka secara bergantian.
Fungsi matematika selalu mengembalikan hasil yang sama ke nilai yang diberikan
Dalam pemrograman imperatif, kami berpikir bahwa fungsi dapat "melakukan" sesuatu atau "menghitung" sesuatu. Fungsi matematika tidak menghitung apa-apa, itu pemetaan murni dari input ke output. Bahkan, definisi lain dari suatu fungsi adalah seperangkat sederhana dari semua pemetaan. Misalnya, sangat mungkin untuk mendefinisikan fungsi "add1" (dalam C #) sebagai
int add1(int input) { switch (input) { case 0: return 1; case 1: return 2; case 2: return 3; case 3: return 4; etc ad infinitum } }
Jelas, tidak mungkin memiliki kasus untuk setiap angka yang mungkin, tetapi prinsipnya sama. Dengan pengaturan ini, tidak ada perhitungan yang dilakukan, hanya pencarian yang dilakukan.
Fungsi matematika bebas dari efek samping
Dalam fungsi matematika, nilai input dan output secara logis adalah dua hal yang berbeda, keduanya telah ditentukan sebelumnya. Fungsi tidak mengubah data input atau output dan hanya memetakan nilai input yang telah ditetapkan dari area definisi ke nilai output yang telah ditentukan di area nilai.
Dengan kata lain, perhitungan fungsi tidak dapat memiliki efek pada input data atau hal lain dari jenisnya . Harus diingat bahwa perhitungan suatu fungsi tidak benar-benar menghitung atau memanipulasi apa pun, itu hanya pencarian yang berlebihan.
"Ketetapan" nilai-nilai ini sangat halus, tetapi pada saat yang sama merupakan hal yang sangat penting. Saat saya berhitung, saya tidak berharap angka akan berubah saat mereka ditambahkan. Misalnya, jika saya punya:
x = 5 y = x+1
Saya tidak berharap x
berubah ketika saya menambahkan 1. Saya berharap untuk mendapatkan nomor yang berbeda ( y
), dan x
harus tetap tidak tersentuh. Dalam dunia matematika, bilangan bulat sudah ada dalam set yang tidak dapat diubah, dan fungsi add1 hanya menentukan hubungan di antara mereka.
Kekuatan fungsi murni
Jenis-jenis fungsi yang memiliki hasil berulang dan tidak memiliki efek samping disebut "fungsi murni," dan Anda dapat melakukan beberapa hal menarik dengannya:
- Mereka mudah diparalelkan. Katakanlah, kita dapat mengambil bilangan bulat dalam rentang 1 hingga 1000 dan mendistribusikannya ke 1000 prosesor yang berbeda, setelah itu kami memerintahkan setiap CPU untuk menjalankan "
add1
" pada angka yang sesuai, sambil memastikan bahwa tidak perlu ada interaksi di antara mereka. Tidak ada kunci, tidak ada mutex, tidak ada semaphores, dll. - Anda dapat menggunakan fungsi dengan malas, menghitungnya jika perlu untuk logika program. Anda dapat yakin bahwa jawabannya akan persis sama, terlepas dari apakah perhitungan dilakukan sekarang atau nanti.
- Anda hanya dapat melakukan perhitungan fungsi untuk input tertentu, dan kemudian menyimpan hasilnya, karena diketahui bahwa nilai input ini akan memberikan output yang sama.
- Jika ada banyak fungsi murni, mereka dapat dihitung dalam urutan apa pun. Sekali lagi, ini tidak dapat mempengaruhi hasil akhir.
Dengan demikian, jika dimungkinkan untuk membuat fungsi murni dalam bahasa pemrograman, Anda dapat segera menerima banyak trik yang kuat. Dan tidak diragukan lagi, semua ini bisa dilakukan di F #:
- Contoh komputasi paralel adalah dalam seri "Mengapa menggunakan F #?" .
- Perhitungan fungsi malas akan dibahas dalam seri Optimasi .
- Hasil fungsi caching disebut memoisasi dan juga akan dibahas dalam seri Optimasi .
- Tidak adanya kebutuhan untuk melacak urutan eksekusi membuat pemrograman paralel jauh lebih mudah dan menghilangkan kebutuhan bug yang disebabkan oleh perubahan urutan fungsi atau refactoring.
"Tidak berguna" sifat fungsi matematika
Fungsi matematika juga memiliki beberapa properti yang sepertinya tidak terlalu berguna saat pemrograman.
- Nilai input dan output tidak dapat diubah
- Fungsi selalu memiliki satu input dan satu output.
Properti ini tercermin dalam desain bahasa pemrograman fungsional. Perlu mempertimbangkannya secara terpisah.
Nilai input dan output tidak dapat diubah
Nilai-nilai yang tidak dapat berubah dalam teori tampak seperti ide yang bagus, tetapi bagaimana cara kerja benar-benar dilakukan jika tidak ada cara untuk menetapkan variabel dengan cara tradisional.
Saya dapat meyakinkan Anda bahwa ini bukan masalah besar yang dapat Anda bayangkan. Dalam seri artikel ini, akan jelas bagaimana ini bekerja dalam praktiknya.
Fungsi matematika selalu memiliki satu input dan satu output.
Seperti dapat dilihat dari diagram, untuk fungsi matematika selalu ada hanya satu input dan hanya satu output. Ini juga berlaku untuk bahasa pemrograman fungsional, meskipun mungkin tidak jelas ketika pertama kali digunakan.
Ini sepertinya ketidaknyamanan yang besar. Bagaimana saya bisa melakukan sesuatu yang bermanfaat tanpa fungsi dengan dua (atau lebih) parameter?
Ternyata ada cara untuk melakukan ini, dan terlebih lagi, itu benar-benar transparan pada F #. Ini disebut "currying", dan layak mendapat pos terpisah, yang akan muncul dalam waktu dekat.
Bahkan, nantinya akan menjadi jelas bahwa dua properti "tidak berguna" ini akan menjadi sangat berharga, dan akan menjadi bagian kunci yang membuat pemrograman fungsional begitu kuat.
Sumber Daya Tambahan
Ada banyak tutorial untuk F #, termasuk materi untuk mereka yang datang dengan pengalaman C # atau Java. Tautan berikut mungkin berguna saat Anda masuk lebih dalam ke F #:
Beberapa cara lain untuk mulai belajar F # juga dijelaskan.
Akhirnya, komunitas F # sangat ramah pemula. Ada obrolan yang sangat aktif di Slack, didukung oleh F # Software Foundation, dengan kamar pemula yang dapat Anda gabung dengan bebas . Kami sangat menyarankan Anda melakukan ini!
Jangan lupa untuk mengunjungi situs komunitas berbahasa Rusia F # ! Jika Anda memiliki pertanyaan tentang belajar bahasa, dengan senang hati kami akan membahasnya di ruang obrolan:
Tentang penulis terjemahan
Diterjemahkan oleh @kleidemos
Perubahan terjemahan dan editorial dilakukan oleh upaya komunitas pengembang F # berbahasa Rusia . Kami juga berterima kasih kepada @schvepsss dan @shwars karena telah menyiapkan artikel ini untuk dipublikasikan.