Bagi saya tampaknya Anda selalu dapat melewati argumen fungsi daripada menggunakan typeclass. Misalnya daripada mendefinisikan typeclass kesetaraan:
class Eq a where
(==) :: a -> a -> Bool
Dan menggunakannya dalam fungsi lain untuk menunjukkan argumen tipe harus merupakan instance dari Eq
:
elem :: (Eq a) => a -> [a] -> Bool
Tidak bisakah kita mendefinisikan elem
fungsi kita tanpa menggunakan typeclass dan alih-alih memberikan argumen fungsi yang berfungsi?
Monad m
kendala mengatakan lebih bagi saya daripada lewat argumen fungsi tambahan jenisa -> m a
danm a -> (a -> m b) -> m b
.TypeApplications
ekstensi memungkinkan Anda membuat argumen implisit eksplisit.(==) @Int 3 5
membandingkan3
dan5
secara khusus sebagaiInt
nilai. Anda dapat menganggap@Int
sebagai kunci dalam kamus fungsi kesetaraan tipe-spesifik, bukanInt
fungsi perbandingan-spesifik itu sendiri.Jawaban:
Iya. Ini disebut "gaya lewat kamus". Kadang-kadang ketika saya melakukan beberapa hal yang sangat rumit, saya perlu membuang typeclass dan mengubahnya menjadi kamus, karena kamus yang lewat lebih kuat 1 , namun seringkali cukup rumit, membuat kode sederhana secara konseptual terlihat cukup rumit. Saya menggunakan gaya passing kamus kadang-kadang dalam bahasa yang bukan Haskell untuk mensimulasikan kacamata ketik (tetapi telah belajar bahwa itu biasanya bukan ide yang bagus seperti kedengarannya).
Tentu saja, setiap kali ada perbedaan dalam kekuatan ekspresif, ada pertukaran. Meskipun Anda dapat menggunakan API yang diberikan dengan lebih banyak cara jika ditulis menggunakan DPS, API mendapatkan lebih banyak informasi jika Anda tidak bisa. Salah satu cara ini muncul dalam praktik adalah dalam
Data.Set
, yang bergantung pada kenyataan bahwa hanya ada satuOrd
kamus per jenis. TheSet
toko elemen diurutkan sesuaiOrd
, dan jika Anda membangun satu set dengan satu kamus, dan kemudian dimasukkan unsur menggunakan satu yang berbeda, seperti akan mungkin dengan DPS, Anda bisa memecahkanSet
's invarian dan menyebabkan kecelakaan. Masalah keunikan ini dapat dikurangi dengan menggunakan hantu eksistensialketik untuk menandai kamus, tetapi, sekali lagi, dengan biaya kompleksitas yang cukup mengganggu di API. Ini juga muncul dengan cara yang hampir sama diTypeable
API.Bit keunikan tidak sering muncul. Apa jenis kacamata yang hebat adalah menulis kode untuk Anda. Sebagai contoh,
yang mengambil dua "prosesor" yang mengambil input dan mungkin memberikan output, dan menggabungkannya, meratakannya
Nothing
, harus ditulis dalam DPS kira-kira seperti ini:Kami pada dasarnya harus mengeja jenis yang kami gunakan lagi, meskipun kami sudah mengeja dalam tanda tangan jenis, dan bahkan itu berlebihan karena kompiler sudah tahu semua jenis. Karena hanya ada satu cara untuk membangun diberikan
Semigroup
pada suatu jenis, kompiler dapat melakukannya untuk Anda. Ini memiliki efek tipe "bunga majemuk" ketika Anda mulai mendefinisikan banyak instance parametrik dan menggunakan struktur tipe Anda untuk menghitung untuk Anda, seperti padaData.Functor.*
kombinator, dan ini digunakan untuk efek yang besar dideriving via
mana Anda pada dasarnya dapat memperoleh semua Struktur aljabar "standar" dari tipe Anda ditulis untuk Anda.Dan bahkan tidak membuat saya mulai menggunakan MPTC dan fundeps, yang memberi informasi kembali ke pemeriksaan ketik dan inferensi. Saya tidak pernah mencoba mengubah hal seperti itu ke DPS - saya menduga itu akan melibatkan banyak bukti kesetaraan - tetapi dalam hal apa pun saya yakin itu akan menjadi lebih banyak pekerjaan untuk otak saya daripada saya akan merasa nyaman dengan.
-
1 U nless Anda gunakan
reflection
dalam hal ini mereka menjadi setara dalam kekuasaan - tetapireflection
juga dapat menjadi rumit untuk digunakan.sumber
Iya. Itu (disebut kamus lewat) pada dasarnya adalah apa yang dilakukan kompiler untuk mengetikkan kacamata. Untuk fungsi itu, dilakukan secara harfiah, akan terlihat sedikit seperti ini:
Memanggil
elemBy (==) x xs
sekarang setara denganelem x xs
. Dan dalam kasus khusus ini, Anda dapat melangkah lebih jauh:eq
memiliki argumen pertama yang sama setiap kali, sehingga Anda dapat menjadikannya sebagai tanggung jawab penelepon untuk menerapkannya, dan berakhir dengan ini:Memanggil
elemBy2 (x ==) xs
sekarang setara denganelem x xs
....Oh tunggu. Itu baru saja
any
. (Dan pada kenyataannya, di perpustakaan standarelem = any . (==)
,.)sumber
implicit
dan kompiler akan menyuntikkannya untuk Anda dari ruang lingkup.