Peringatan yang adil, saya baru mengenal pemrograman fungsional sehingga saya dapat memiliki banyak asumsi buruk.
Saya sudah belajar tentang tipe aljabar. Banyak bahasa fungsional tampaknya memilikinya, dan mereka cukup berguna dalam hubungannya dengan pencocokan pola. Namun, masalah apa yang sebenarnya mereka pecahkan? Saya dapat mengimplementasikan tipe aljabar yang tampaknya (semacam) dalam C # seperti ini:
public abstract class Option { }
public class None : Option { }
public class Some<T> : Option
{
public T Value { get; set; }
}
var result = GetSomeValue();
if(result is None)
{
}
else
{
}
Tapi saya pikir sebagian besar akan setuju ini adalah program pemrograman berorientasi objek, dan Anda tidak boleh melakukannya. Jadi, apakah pemrograman fungsional hanya menambahkan sintaks yang lebih bersih yang membuat gaya pemrograman ini tampak kurang kotor? Apa lagi yang saya lewatkan?
functional-programming
algebraic-data-type
ConditionRacer
sumber
sumber
class ThirdOption : Option{}
dan memberi Andanew ThirdOption()
tempat yang Anda harapkanSome
atauNone
?data Maybe a = Just a | Nothing
(setara dengandata Option a = Some a | None
dalam contoh Anda): Anda tidak dapat menambahkan kasus ketiga post-hoc. Meskipun Anda dapat mengurutkan jenis penjiplakan dalam C # dengan cara yang Anda perlihatkan, itu bukan yang tercantik.Jawaban:
Kelas dengan antarmuka dan warisan menyajikan dunia terbuka: Siapa saja dapat menambahkan jenis data baru. Untuk antarmuka yang diberikan, mungkin ada kelas yang mengimplementasikannya di seluruh dunia, dalam file yang berbeda, dalam proyek yang berbeda, di perusahaan yang berbeda. Mereka membuatnya mudah untuk menambahkan kasus ke struktur data, tetapi karena implementasi antarmuka terdesentralisasi, sulit untuk menambahkan metode baru ke antarmuka. Setelah antarmuka publik, pada dasarnya membeku. Tidak ada yang tahu semua kemungkinan implementasi.
Tipe data aljabar adalah ganda untuk itu, mereka tertutup . Semua kasus data terdaftar di satu tempat dan operasi tidak hanya dapat mencantumkan varian secara mendalam, mereka didorong untuk melakukannya. Akibatnya menulis fungsi baru yang beroperasi pada tipe data aljabar adalah sepele: Cukup tulis fungsi sialan itu. Sebagai gantinya, menambahkan case baru itu rumit karena Anda harus membahas seluruh basis kode dan memperpanjang setiap dasarnya
match
. Mirip dengan situasi dengan antarmuka, di perpustakaan standar Rust, menambahkan varian baru adalah perubahan besar (untuk tipe publik).Ini adalah dua sisi masalah ekspresi . Tipe data aljabar adalah solusi yang tidak lengkap untuk mereka, tetapi begitu juga OOP. Keduanya memiliki keuntungan tergantung pada berapa banyak kasus data yang ada, seberapa sering kasus tersebut berubah, dan seberapa sering operasi diperpanjang atau diubah. (Itulah sebabnya banyak bahasa modern menyediakan keduanya, atau sesuatu yang serupa, atau langsung menuju mekanisme yang lebih kuat dan lebih rumit yang mencoba untuk merangkum kedua pendekatan.)
sumber
Itu mungkin penyederhanaan, tapi ya.
Mari kita perjelas jenis data aljabar apa (ringkasan tautan baik ini dari Learn you as Haskell):
contoh Anda hanya benar-benar berfungsi dengan yang pertama.
Apa yang mungkin Anda lewatkan adalah bahwa dengan menyediakan dua operasi dasar ini, bahasa fungsional memungkinkan Anda membangun yang lainnya. C # memiliki struct, kelas, enum, generik di atasnya, dan tumpukan aturan untuk mengatur bagaimana hal-hal ini berperilaku.
Dikombinasikan dengan beberapa sintaks untuk membantu, bahasa fungsional dapat menguraikan operasi ke dua jalur ini, memberikan pendekatan yang bersih, sederhana dan elegan untuk jenis.
Mereka memecahkan masalah yang sama dengan sistem tipe lainnya: "nilai apa yang legal untuk digunakan di sini?" - mereka hanya mengambil pendekatan berbeda untuk itu.
sumber
Mungkin mengejutkan Anda mengetahui bahwa pencocokan pola tidak dianggap sebagai cara paling idiomatis untuk bekerja dengan Opsi. Lihat dokumentasi Pilihan Scala untuk lebih lanjut tentang itu. Saya tidak yakin mengapa begitu banyak tutorial KB mendorong penggunaan ini.
Sebagian besar yang Anda lewatkan adalah ada sejumlah fungsi yang dibuat untuk membuat bekerja dengan Opsi lebih mudah. Pertimbangkan contoh utama dari dokumen Scala:
Perhatikan bagaimana
map
danfilter
membiarkan Anda menjalankan operasi pada Opsi, tanpa harus memeriksa pada setiap titik apakah Anda memilikinyaNone
atau tidak. Kemudian pada akhirnya, Anda gunakangetOrElse
untuk menentukan nilai default. Tidak ada gunanya Anda melakukan sesuatu yang "kotor" seperti memeriksa jenis. Pemeriksaan tipe yang tidak dapat dihindari dilakukan secara internal ke perpustakaan. Haskell memiliki set fungsi analagous sendiri, belum lagi set besar fungsi yang akan bekerja pada monad atau functor.Tipe data aljabar lainnya memiliki cara idiomatis sendiri untuk bekerja dengannya, dan pencocokan pola rendah pada tiang totem dalam banyak kasus. Demikian juga, ketika Anda membuat tipe Anda sendiri, Anda diharapkan untuk menyediakan fungsi serupa untuk bekerja dengannya.
sumber