Saya membaca tentang pemrograman fungsional dan saya perhatikan bahwa Pencocokan Pola disebutkan dalam banyak artikel sebagai salah satu fitur inti dari bahasa fungsional.
Dapatkah seseorang menjelaskan untuk pengembang Java / C ++ / JavaScript apa artinya?
Jawaban:
Memahami pencocokan pola memerlukan penjelasan tiga bagian:
Singkatnya, tipe data aljabar
Bahasa fungsional mirip-ML memungkinkan Anda menentukan tipe data sederhana yang disebut "disjoint unions" atau "tipe data aljabar". Struktur data ini adalah wadah sederhana, dan dapat didefinisikan secara rekursif. Sebagai contoh:
mendefinisikan struktur data seperti stack. Anggap itu setara dengan C # ini:
Jadi,
Cons
danNil
pengidentifikasi mendefinisikan kelas sederhana, di manaof x * y * z * ...
mendefinisikan konstruktor dan beberapa tipe data. Parameter ke konstruktor tidak disebutkan namanya, mereka diidentifikasi oleh posisi dan tipe data.Anda membuat instance
a list
kelas Anda seperti itu:Yang sama dengan:
Pencocokan pola singkatnya
Pencocokan pola adalah sejenis pengujian tipe. Jadi katakanlah kita membuat objek stack seperti yang di atas, kita dapat menerapkan metode untuk mengintip dan meletupkan stack sebagai berikut:
Metode di atas setara (meskipun tidak diterapkan seperti itu) dengan C # berikut:
(Hampir selalu, bahasa ML menerapkan pencocokan pola tanpa menjalankan jenis-tes atau gips, sehingga kode C # agak menipu. Mari menyikat detail implementasi dengan beberapa lambaian tangan :))
Singkatnya, struktur data dekomposisi
Ok, mari kembali ke metode mengintip:
Kuncinya adalah memahami bahwa
hd
dantl
pengidentifikasi adalah variabel (errm ... karena mereka tidak berubah, mereka tidak benar-benar "variabel", tetapi "nilai";)). Jikas
memiliki tipeCons
, maka kita akan menarik nilainya keluar dari konstruktor dan mengikatnya ke variabel bernamahd
dantl
.Pencocokan pola berguna karena memungkinkan kita menguraikan struktur data berdasarkan bentuknya, bukan kontennya . Jadi bayangkan jika kita mendefinisikan pohon biner sebagai berikut:
Kita dapat mendefinisikan beberapa rotasi pohon sebagai berikut:
(
let rotateRight = function
Konstruktornya adalah gula sintaksis untuklet rotateRight s = match s with ...
.)Jadi selain mengikat struktur data ke variabel, kita juga bisa menelusuri ke dalamnya. Katakanlah kita memiliki simpul
let x = Node(Nil, 1, Nil)
. Jika kami memanggilrotateLeft x
, kami mengujix
terhadap pola pertama, yang gagal mencocokkan karena anak yang tepat memiliki jenis,Nil
bukanNode
. Ini akan pindah ke pola berikutnyax -> x
,, yang akan cocok dengan input apa pun dan mengembalikannya tanpa dimodifikasi.Sebagai perbandingan, kami akan menulis metode di atas dalam C # sebagai:
Untuk yang serius.
Pencocokan pola mengagumkan
Anda dapat menerapkan sesuatu yang mirip dengan pencocokan pola dalam C # menggunakan pola pengunjung , tetapi tidak hampir fleksibel karena Anda tidak dapat secara efektif menguraikan struktur data yang kompleks. Selain itu, jika Anda menggunakan pencocokan pola, kompiler akan memberi tahu Anda jika Anda meninggalkan kasing . Seberapa hebat itu?
Pikirkan tentang bagaimana Anda akan menerapkan fungsionalitas serupa dalam C # atau bahasa tanpa pencocokan pola. Pikirkan tentang bagaimana Anda akan melakukannya tanpa tes-tes dan gips saat runtime. Ini tentu tidak sulit , hanya rumit dan tebal. Dan Anda tidak memiliki pemeriksa memeriksa untuk memastikan Anda telah menutupi setiap kasus.
Jadi pencocokan pola membantu Anda menguraikan dan menavigasi struktur data dalam sintaksis yang sangat nyaman dan ringkas, memungkinkan kompiler untuk memeriksa logika kode Anda, setidaknya sedikit. Ini benar - benar fitur pembunuh.
sumber
Jawaban singkat: Pencocokan pola muncul karena bahasa fungsional memperlakukan tanda sama dengan sebagai pernyataan kesetaraan alih-alih penugasan.
Jawaban panjang: Pencocokan pola adalah bentuk pengiriman berdasarkan pada "bentuk" dari nilai yang diberikannya. Dalam bahasa fungsional, tipe data yang Anda tetapkan biasanya apa yang dikenal sebagai serikat terdiskriminasi atau tipe data aljabar. Misalnya, apa itu daftar (ditautkan)? Daftar yang ditautkan
List
hal-hal dari beberapa jenisa
adalah daftar kosongNil
atau beberapa elemen jenisa
Cons
ed keList a
(daftara
s). Di Haskell (bahasa fungsional yang paling saya kenal), kami menulis iniSemua serikat yang didiskriminasi didefinisikan dengan cara ini: satu tipe memiliki sejumlah cara berbeda untuk membuatnya; pencipta, seperti
Nil
dan diCons
sini, disebut konstruktor. Ini berarti bahwa nilai dari tipe tersebutList a
dapat dibuat dengan dua konstruktor yang berbeda — ia dapat memiliki dua bentuk yang berbeda. Jadi misalkan kita ingin menulishead
fungsi untuk mendapatkan elemen pertama dari daftar. Di Haskell, kami akan menulis ini sebagaiKarena
List a
nilai dapat dari dua jenis yang berbeda, kita perlu menangani masing-masing secara terpisah; ini adalah pencocokan pola. Dihead x
, jikax
cocok dengan polanyaNil
, maka kita menjalankan case pertama; jika cocok dengan polaCons h _
, kita jalankan yang kedua.Jawaban singkat, menjelaskan: Saya pikir salah satu cara terbaik untuk berpikir tentang perilaku ini adalah dengan mengubah cara Anda berpikir tentang tanda sama dengan. Dalam bahasa kurung kurung, pada umumnya,
=
menunjukkan penugasan:a = b
berarti "membuata
menjadib
." Dalam banyak bahasa fungsional, bagaimanapun,=
menunjukkan pernyataan kesetaraan:let Cons a (Cons b Nil) = frob x
menegaskan bahwa hal di sebelah kiri,Cons a (Cons b Nil)
setara dengan hal di sebelah kananfrob x
; selain itu, semua variabel yang digunakan di sebelah kiri menjadi terlihat. Ini juga yang terjadi dengan argumen fungsi: kami menyatakan bahwa argumen pertama terlihatNil
, dan jika tidak, kami terus memeriksa.sumber
Cons
artinyaCons
adalah traktor kontra yang membangun daftar (ditautkan) dari kepala (thea
) dan ekor (theList a
). Nama itu berasal dari Lisp. Di Haskell, untuk tipe daftar bawaan, itu adalah:
operator (yang masih diucapkan "kontra").Artinya bukan menulis
Kamu bisa menulis
Hei, C ++ juga mendukung pencocokan pola.
sumber
Pencocokan pola adalah semacam metode overload pada steroid. Kasus paling sederhana akan sama kira-kira sama dengan apa yang Anda lihat di java, argumen adalah daftar tipe dengan nama. Metode yang benar untuk panggilan didasarkan pada argumen yang diteruskan, dan berfungsi ganda sebagai penugasan argumen tersebut ke nama parameter.
Pola hanya selangkah lebih maju, dan dapat merusak argumen yang diteruskan lebih jauh. Itu juga bisa berpotensi menggunakan penjaga untuk benar-benar cocok berdasarkan nilai argumen. Untuk menunjukkan, saya akan berpura-pura seperti JavaScript yang cocok dengan pola.
Dalam foo2, ia mengharapkan a menjadi array, ia memecah argumen kedua, mengharapkan sebuah objek dengan dua alat peraga (prop1, prop2) dan memberikan nilai-nilai dari properti tersebut ke variabel d dan e, dan kemudian mengharapkan argumen ketiga menjadi 35.
Tidak seperti dalam JavaScript, bahasa dengan pencocokan pola biasanya memungkinkan beberapa fungsi dengan nama yang sama, tetapi pola yang berbeda. Dengan cara ini seperti metode overloading. Saya akan memberi contoh di erlang:
Kaburkan sedikit mata Anda dan Anda bisa membayangkan ini dalam javascript. Sesuatu seperti ini mungkin:
Intinya adalah bahwa ketika Anda memanggil fibo, implementasi yang digunakan didasarkan pada argumen, tetapi di mana Java terbatas pada tipe sebagai satu-satunya cara overloading, pencocokan pola dapat melakukan lebih banyak.
Di luar fungsi yang berlebihan seperti yang ditunjukkan di sini, prinsip yang sama dapat diterapkan di tempat lain, seperti pernyataan kasus atau penghancuran perjanjian. JavaScript bahkan memiliki ini dalam 1.7 .
sumber
Pencocokan pola memungkinkan Anda untuk mencocokkan nilai (atau objek) dengan beberapa pola untuk memilih cabang kode. Dari sudut pandang C ++, mungkin terdengar sedikit mirip dengan
switch
pernyataan. Dalam bahasa fungsional, pencocokan pola dapat digunakan untuk mencocokkan pada nilai-nilai primitif standar seperti bilangan bulat. Namun, ini lebih berguna untuk tipe yang dikomposisikan.Pertama, mari kita tunjukkan pencocokan pola pada nilai-nilai primitif (menggunakan extended pseudo-C ++
switch
):Penggunaan kedua berkaitan dengan tipe data fungsional seperti tupel (yang memungkinkan Anda untuk menyimpan beberapa objek dalam nilai tunggal) dan serikat terdiskriminasi yang memungkinkan Anda untuk membuat tipe yang dapat berisi salah satu dari beberapa opsi. Ini terdengar agak seperti
enum
kecuali bahwa setiap label juga dapat membawa beberapa nilai. Dalam sintaks pseudo-C ++:Nilai tipe
Shape
sekarang dapat berisiRectangle
semua koordinat atau aCircle
dengan pusat dan jari-jari. Pencocokan pola memungkinkan Anda menulis fungsi untuk bekerja denganShape
jenis:Terakhir, Anda juga dapat menggunakan pola bersarang yang menggabungkan kedua fitur. Misalnya, Anda bisa menggunakan
Circle(0, 0, radius)
untuk mencocokkan semua bentuk yang memiliki pusat di titik [0, 0] dan memiliki jari-jari apa pun (nilai jari-jari akan ditetapkan ke variabel baruradius
).Ini mungkin terdengar agak asing dari sudut pandang C ++, tapi saya harap pseudo-C ++ saya membuat penjelasannya menjadi jelas. Pemrograman fungsional didasarkan pada konsep yang sangat berbeda, sehingga lebih masuk akal dalam bahasa fungsional!
sumber
Pencocokan pola adalah tempat juru bahasa untuk bahasa Anda akan memilih fungsi tertentu berdasarkan pada struktur dan konten argumen yang Anda berikan.
Ini bukan hanya fitur bahasa fungsional tetapi tersedia untuk banyak bahasa berbeda.
Pertama kali saya menemukan ide adalah ketika saya belajar prolog di mana itu benar-benar pusat bahasa.
misalnya
Kode di atas akan memberikan item terakhir dari daftar. Input arg adalah yang pertama dan hasilnya adalah yang kedua.
Jika hanya ada satu item dalam daftar interpreter akan memilih versi pertama dan argumen kedua akan disetel sama dengan yang pertama yaitu nilai akan ditugaskan untuk hasilnya.
Jika daftar memiliki kepala dan ekor, penafsir akan memilih versi kedua dan berulang sampai hanya ada satu item yang tersisa dalam daftar.
sumber
Bagi banyak orang, mengambil konsep baru lebih mudah jika beberapa contoh mudah diberikan, jadi di sini kita mulai:
Katakanlah Anda memiliki daftar tiga bilangan bulat, dan ingin menambahkan elemen pertama dan ketiga. Tanpa pencocokan pola, Anda bisa melakukannya seperti ini (contoh di Haskell):
Sekarang, meskipun ini adalah contoh mainan, bayangkan kami ingin mengikat integer pertama dan ketiga ke variabel dan menjumlahkannya:
Ekstraksi nilai-nilai dari struktur data inilah yang dilakukan pencocokan pola. Anda pada dasarnya "mencerminkan" struktur sesuatu, memberikan variabel untuk mengikat tempat-tempat menarik:
Ketika Anda memanggil fungsi ini dengan [1,2,3] sebagai argumennya, [1,2,3] akan disatukan dengan [pertama
_
,, ketiga], mengikat pertama ke 1, ketiga ke 3 dan membuang 2 (_
adalah placeholder untuk hal-hal yang tidak Anda pedulikan).Sekarang, jika Anda hanya ingin mencocokkan daftar dengan 2 sebagai elemen kedua, Anda dapat melakukannya seperti ini:
Ini hanya akan berfungsi untuk daftar dengan 2 sebagai elemen kedua dan memberikan pengecualian, karena tidak ada definisi untuk addFirstAndThird yang diberikan untuk daftar yang tidak cocok.
Sampai sekarang, kami menggunakan pencocokan pola hanya untuk pengikatan yang merusak. Di atas itu, Anda dapat memberikan beberapa definisi fungsi yang sama, di mana definisi pencocokan pertama digunakan, dengan demikian, pencocokan pola sedikit seperti "pernyataan switch pada stereoids":
addFirstAndThird akan dengan senang hati menambahkan elemen pertama dan ketiga dari daftar dengan 2 sebagai elemen kedua mereka, dan jika tidak, "gagal" dan "kembali" 0. Fungsionalitas "seperti switch" ini tidak hanya dapat digunakan dalam definisi fungsi, misalnya:
Lebih lanjut, ini tidak terbatas pada daftar, tetapi dapat digunakan dengan tipe lain juga, misalnya mencocokkan konstruktor nilai Just and Nothing dari tipe Maybe untuk "membuka" nilai:
Tentu, itu hanya contoh mainan, dan saya bahkan tidak mencoba memberikan penjelasan formal atau lengkap, tetapi mereka harus cukup memahami konsep dasar.
sumber
Anda harus mulai dengan halaman Wikipedia yang memberikan penjelasan yang cukup bagus. Kemudian, baca bab wikibook Haskell yang relevan .
Ini adalah definisi yang bagus dari wikibook di atas:
sumber
Berikut adalah contoh yang sangat singkat yang menunjukkan kegunaan pencocokan pola:
Katakanlah Anda ingin mengurutkan elemen dalam daftar:
ke (Saya sudah beres "New York")
dalam bahasa yang lebih penting Anda akan menulis:
Dalam bahasa fungsional Anda malah menulis:
Karena Anda dapat melihat solusi yang cocok dengan pola memiliki lebih sedikit noise, Anda dapat dengan jelas melihat kasus-kasus yang berbeda dan betapa mudahnya melakukan perjalanan dan mengubah struktur daftar kami.
Saya telah menulis posting blog yang lebih rinci tentang hal ini di sini .
sumber