List karakter dan pencarian berurutan yang digunakan sepanjang jalur ini mudah dibaca, tetapi kode produksi memilih struktur yang lebih hemat waktu dan memori. Dua kelompok pustaka mengisi tempat itu, yaitu text untuk teks yang lebih efisien daripada String, serta containers untuk peta dan himpunan yang menggantikan pencarian pada list. Topik ini membahas alasan pergeserannya, penggunaan dasar keduanya, dan titik pertemuan yang paling sering muncul pada program nyata.
Dari String ke Text#
Tipe String pada Haskell adalah list karakter, sehingga penyambungannya menyalin seluruh list dan panjangnya hanya diketahui setelah seluruh sel dihitung. Tipe Text dari pustaka text menyimpan teks dalam bentuk yang lebih padat, sehingga panjangnya cepat dihitung dan penyambungannya tidak menyalin dari awal. Konversi antara keduanya berlangsung melalui T.pack dan T.unpack, dan berkas berikut memperlihatkan pemakaiannya.
{-# LANGUAGE OverloadedStrings #-}
import qualified Data.Map.Strict as M
import qualified Data.Text as T
frekuensi :: [T.Text] -> M.Map T.Text Int
frekuensi = foldr (\kata -> M.insertWith (+) kata 1) M.empty
main :: IO ()
main = do
let teks = "pisang apel pisang jeruk apel"
print (T.length teks)
print (M.lookup "pisang" (frekuensi (T.words teks)))
print (frekuensi (T.words teks))29
Just 2
fromList [("apel",2),("jeruk",1),("pisang",2)]Pragmatik OverloadedStrings membuat literal seperti "pisang" bertipe Text tanpa pemanggilan T.pack di setiap tempat, karena compiler menerjemahkan literal string ke tipe apa pun yang memiliki instans IsString. Pemanggilan fungsi tetap menggunakan nama qualified, yaitu T.length dan T.words, kebiasaan yang menjadi konvensi pustaka ini agar asal setiap fungsi tetap terbaca. Fungsi-fungsi yang dikenal pada list kebanyakan memiliki padanannya di sini, sehingga perpindahan dari String lebih menyangkut tipe hasil daripada cara berpikir baru.
Keuntungan Text paling terasa pada pekerjaan yang menyentuh teks panjang berulang kali, misalnya menghitung panjang, memotong, dan menyambung pada satu teks yang sama. Pada String, setiap operasi menyalin list karakternya, sedangkan Text bekerja pada blok memori yang padat sehingga porsinya lebih kecil dan memorinya lebih sedikit. Biaya konversi di batas hanya dibayar sekali, keadaan yang membuat aturan menahan konversi di tepi program konsisten dengan tujuan pustakanya.
Peta pada containers#
Pustaka containers menyediakan Map untuk padanan kamus dan Set untuk himpunan, keduanya dibangun di atas pohon seimbang sehingga pencariannya berjalan pada waktu logaritmik, jauh di depan penyusuran list. Modul Data.Map.Strict dipilih ketika nilai tidak perlu ditunda evaluasinya, karena setiap pembaruan langsung menghitung nilai baru dan mencegah penumpukan thunk.
# cari kunci pada peta
ghc -e 'Data.Map.Strict.lookup "b" (Data.Map.Strict.fromList [("a", 1 :: Int), ("b", 2)])'
# ukur peta setelah penyisipan kunci baru
ghc -e 'Data.Map.Strict.size (Data.Map.Strict.insert "c" 3 (Data.Map.Strict.fromList [("a", 1 :: Int), ("b", 2)]))'Just 2
3Kembalian lookup berupa Maybe, yaitu Just berisi nilai apabila kuncinya ada dan Nothing apabila tidak, sehingga pencarian kunci yang absen tidak melempar exception, melainkan menjadi keadaan yang wajib ditangani. Fungsi insertWith pada program rekap-kata memanfaatkan bentuk lain dari pola itu, yaitu menyisipkan nilai bawaan 1 dan menggabungkannya dengan nilai lama apabila kuncinya sudah ada, bentuk yang membuat penghitungan frekuensi menjadi satu baris. Pemanggilan print pada peta menampilkan isi yang tersusun menurut kunci, sifat bawaan struktur pohonnya.
Pustaka containers juga menyediakan Set untuk himpunan dengan pola yang sama, yaitu member, insert, dan delete yang seluruhnya berjalan pada waktu logaritmik. Pemilihan antara Map dan Set mengikuti kebutuhan data, yaitu peta digunakan apabila setiap kunci membawa nilai, sedangkan himpunan digunakan apabila yang penting hanyalah keanggotaannya. Himpunan juga menyediakan operasi gabungan dan irisan yang biayanya proporsional terhadap ukuran hasilnya, dan kedua operasi itu berbagi syarat yang sama, yaitu kuncinya harus memiliki instans Ord agar urutan internal pohonnya dapat ditetapkan.
Titik pertemuan keduanya#
Program rekap-kata pada bagian pertama menunjukkan pola yang paling sering muncul pada kode nyata, yaitu teks masukan dipecahkan menjadi list Text, lalu hasilnya dikumpulkan menjadi peta. Setiap tahap berada pada tipe yang tepat, yaitu Text untuk teks dan Map untuk padanan kunci-nilai, sedangkan list tetap digunakan sebagai urutan sementara di antara keduanya. Pola ini juga menjadi bentuk paling awal dari pemrosesan data terstruktur, dan pembahasan JSON melanjutkan alur yang sama menuju pertukaran data antarprogram.
Kesalahan umum#
Kesalahan pertama adalah mencampur String dan Text tanpa konversi, keadaan yang ditolak compiler dengan pesan ketidakcocokan tipe antara [Char] dan Text. Konversi T.pack dan T.unpack menyelesaikannya, tetapi kebiasaan yang lebih baik berupa memilih satu tipe untuk satu lapisan program dan menahan konversi di batasnya, misalnya membaca berkas sebagai Text lalu memprosesnya sebagai Text sampai selesai.
Kesalahan kedua berupa memodelkan pasangan kunci-nilai sebagai list pasangan yang disusuri dengan lookup list. Cara itu bekerja untuk beberapa entri, tetapi biayanya tumbuh sebanding dengan panjang list, sedangkan Map menjaga pencariannya tetap cepat pada ukuran berapa pun. Kesalahan ketiga berupa menggunakan Data.Map.Lazy untuk akumulator yang diperbarui ribuan kali, karena nilai tertunda menumpuk pada setiap pembaruan, dan pilihan Data.Map.Strict menghindari penumpukan itu sejak awal.
Ringkasan#
Textmenyimpan teks secara padat dengan konversiT.packdanT.unpack, dan pragmatikOverloadedStringsmembuat literalnya ringkas.Data.Map.Strictmenyediakan pencarian logaritmik dengan kembalianMaybe, sertainsertWithuntuk akumulasi frekuensi dalam satu baris.ByteStringmenampung byte mentah, sedangkanTextmenampung teks untuk manusia, dan keduanya tidak saling menggantikan.- Pola yang lazim berupa memecah
Textmenjadi list, lalu mengumpulkannya menjadiMap, dengan konversi yang ditahan di batas lapisan.
Referensi#
- Data.Text — Hackage
— Dokumentasi tipe
Textbeserta fungsi kuncinya. - Data.Map.Strict — Hackage
— Dokumentasi peta strict pada pustaka
containers. - Data.ByteString — Hackage — Dokumentasi urutan byte untuk berkas dan jaringan.
- OverloadedStrings — GHC Users Guide
— Dokumentasi pragmatik yang memungkinkan literal string bertipe
Text.