Topik ini membahas ekspresi match, yaitu mekanisme utama pencocokan pola (pattern matching) di F#. Pembahasan mencakup match sebagai ekspresi yang menghasilkan nilai, urutan pengecekan pola dari atas ke bawah, peringatan compiler untuk kasus yang terlewat, serta wildcard _ dan letak terakhirnya. Setelah topik ini dibaca, pencabangan beruntun if dan else if dapat ditulis ulang menjadi match yang kelengkapannya diperiksa compiler, yaitu program yang memeriksa dan menerjemahkan kode.
Match sebagai ekspresi#
Ekspresi match membandingkan sebuah nilai dengan serangkaian pola dari atas ke bawah dan menghasilkan nilai dari pola pertama yang cocok. Strukturnya diawali kata kunci match, diikuti nilai yang dicocokkan dan kata with, kemudian barisan arm, yaitu cabang pencocokan berbentuk | pola -> ekspresi. Karena match adalah ekspresi, hasilnya dapat diikat dengan let atau langsung digunakan oleh ekspresi lain. Seluruh arm pada satu match wajib menghasilkan tipe yang sama, sehingga compiler menolak match yang mengembalikan string pada satu arm dan bilangan pada arm lainnya.
Berkas berikut mengklasifikasikan nomor hari menjadi nama harinya sekaligus jenis harinya. Pola literal seperti | 1 -> hanya cocok untuk satu nilai, sedangkan pola gabungan seperti | 1 | 2 | 3 | 4 | 5 -> cocok untuk salah satu nilai yang ditulisnya. Arm | _ -> pada kedua fungsi menampung nilai di luar 1 sampai 7, dan perannya dibahas lebih rinci di bagian akhir.
// Klasifikasi nomor hari dengan pola literal dan pola gabungan
let namaHari nomor =
match nomor with
| 1 -> "Senin"
| 2 -> "Selasa"
| 3 -> "Rabu"
| 4 -> "Kamis"
| 5 -> "Jumat"
| 6 -> "Sabtu"
| 7 -> "Minggu"
| _ -> "bukan nomor hari"
let jenisHari nomor =
match nomor with
| 1 | 2 | 3 | 4 | 5 -> "hari kerja"
| 6 | 7 -> "akhir pekan"
| _ -> "bukan nomor hari"
printfn "hari ke-3 adalah %s" (namaHari 3)
printfn "hari ke-6 adalah %s" (namaHari 6)
printfn "hari ke-9 adalah %s" (namaHari 9)
printfn "hari ke-6 termasuk %s" (jenisHari 6)
printfn "hari ke-3 termasuk %s" (jenisHari 3)hari ke-3 adalah Rabu
hari ke-6 adalah Sabtu
hari ke-9 adalah bukan nomor hari
hari ke-6 termasuk akhir pekan
hari ke-3 termasuk hari kerjaUrutan pola dari atas ke bawah#
Pola dicek satu per satu mulai dari arm paling atas, dan arm pertama yang cocok menentukan hasilnya. Aturan ini menjadi penting apabila lebih dari satu pola dapat cocok untuk nilai yang sama, misalnya pola literal | 0 -> dan pola yang menampung semua nilai. Diagram berikut memperlihatkan alurnya pada match dengan dua pola, yaitu pola literal yang tidak cocok lalu pola wildcard yang cocok.
Berkas berikut menempatkan pola literal | 0 -> di atas arm pengikat | angka ->. Arm pengikat cocok untuk semua nilai dan mengikat nilainya ke nama angka, sehingga arm seperti ini hanya tepat berada setelah pola yang lebih spesifik. Keluarannya menunjukkan bahwa 0 tertangkap di arm pertama, sedangkan 5 jatuh ke arm kedua dan nilainya dibentuk menjadi teks.
// Pola dicek dari atas ke bawah, arm pertama yang cocok dipakai
let deskripsikan angka =
match angka with
| 0 -> "nol"
| angka -> sprintf "bukan nol, yaitu %d" angka
printfn "%s" (deskripsikan 0)
printfn "%s" (deskripsikan 5)nol
bukan nol, yaitu 5Apabila urutan dibalik, arm yang paling umum menutup semua arm sesudahnya. Compiler mendeteksi kondisi ini dan menerbitkan peringatan FS0026 yang menyatakan bahwa sebuah arm tidak akan pernah dicocokkan. Skrip pola-terbalik.fsx berikut memperlihatkan kondisi tersebut. Peringatan itu tetap muncul meskipun program berjalan, dan nilai 0 bahkan dikembalikan sebagai bukan nol karena wildcard menang lebih dahulu.
# tampilkan isi berkas skripnya
cat pola-terbalik.fsx
# jalankan skripnya dari folder topik
dotnet fsi pola-terbalik.fsx// Urutan pola dibalik, arm paling umum berada paling atas
let deskripsikan angka =
match angka with
| _ -> "bukan nol"
| 0 -> "nol"
printfn "angka 0: %s" (deskripsikan 0)
/home/kal/my-project/content/fsharp/pattern-matching/ekspresi-match/pola-terbalik.fsx(5,7): warning FS0026: This rule will never be matched
angka 0: bukan nolPeringatan untuk kasus yang terlewat#
Compiler F# memeriksa kelengkapan pencocokan pola pada setiap match, yaitu memastikan tidak ada kemungkinan nilai yang lolos dari semua pola. Apabila ada, compiler menerbitkan peringatan FS0025 pada waktu kompilasi dan menyebutkan salah satu contoh nilai yang terlewat. Pemeriksaan ini berlaku pada pola literal karena himpunan nilai bilangan bulat jauh lebih besar daripada literal yang ditulis.
Skrip peringatan.fsx di bawah ini sengaja dibuat tidak lengkap, yaitu hanya mencantumkan literal 0, 1, dan 2 untuk status peminjaman koleksi. Keluarannya memuat peringatan asli dari compiler, dan peringatan tersebut diharapkan karena polanya memang kurang. Jalur berkas beserta posisi baris di awal pesan menunjukkan letak match yang memicunya, sedangkan contoh nilai 3 adalah salah satu kasus yang tidak tercakup.
# tampilkan isi berkas skripnya
cat peringatan.fsx
# jalankan skripnya dari folder topik
dotnet fsi peringatan.fsx// Match tanpa wildcard dan tanpa semua kasus literal
let status = 1
let keterangan =
match status with
| 0 -> "tersedia"
| 1 -> "dipinjam"
| 2 -> "hilang"
printfn "status %d = %s" status keterangan
/home/kal/my-project/content/fsharp/pattern-matching/ekspresi-match/peringatan.fsx(4,11): warning FS0025: Incomplete pattern matches on this expression. For example, the value '3' may indicate a case not covered by the pattern(s).
status 1 = dipinjamCara perbaikannya ada dua, yaitu mencantumkan kasus yang hilang satu per satu atau menutup match dengan pola penutup di arm terakhir. Versi yang ditutup wildcard berikut ini berjalan tanpa peringatan, dan keterangan untuk nilai di luar 0 sampai 2 juga disediakan.
let status = 1
let keterangan =
match status with
| 0 -> "tersedia"
| 1 -> "dipinjam"
| 2 -> "hilang"
| _ -> "status tidak dikenal"
printfn "status %d = %s" status keteranganstatus 1 = dipinjamWildcard dan letak terakhirnya#
Wildcard _ cocok untuk semua nilai tanpa mengikat nilainya ke nama mana pun. Arm yang ditulis setelah wildcard tidak akan pernah tercapai, sehingga wildcard selalu diletakkan paling akhir. Posisi yang keliru tidak luput dari pemeriksaan compiler karena FS0026 yang diperlihatkan pada bagian sebelumnya memperingatkan arm yang tak terjangkau.
Pilihan antara wildcard dan arm pengikat ditentukan oleh penggunaan nilainya. Gunakan wildcard apabila nilai sisanya tidak dibaca, seperti arm | _ -> pada nama-hari.fsx yang balikannya sama untuk semua nilai lain. Gunakan arm pengikat apabila nilainya digunakan, seperti | angka -> pada urutan-pola.fsx yang membentuk teks dari nilai tersebut. Keduanya sama-sama berperan sebagai penutup match, dan kehadirannya membuat pola-pola spesifik di atasnya tidak menimbulkan peringatan kelengkapan.
Ringkasan#
- Ekspresi match mengecek pola dari atas ke bawah dan menghasilkan nilai dari arm pertama yang cocok, sehingga seluruh arm wajib bertipe sama.
- Arm paling umum, baik wildcard maupun arm pengikat, diletakkan paling bawah, dan compiler menerbitkan FS0026 bila arm sesudahnya tidak terjangkau.
- Peringatan FS0025 menandai kemungkinan nilai yang tidak tercakup dan disertai contoh nilai apabila polanya berupa literal.
- Wildcard
_menampung semua nilai tanpa mengikat, dan penempatannya di akhir menjaga arm di atasnya tetap terjangkau.
Referensi#
- Match expressions — Microsoft Learn — Dokumentasi resmi ekspresi match beserta aturan arm dan polanya.
- Pattern matching — Microsoft Learn — Daftar jenis pola di F#, termasuk pola wildcard, literal, dan pola gabungan.