Anda dapat menggeneralisasi definisi kelas HavingField
; khususnya, Anda dapat mengekspresikan hubungan antara variabel tipe yang diperbarui dan tipe rekaman menggunakan dependensi fungsional. Hal ini memungkinkan variabel tipe pembaruan terjadi di posisi mana pun; dan itu memungkinkan pembaruan pada bidang monomorfik.
class FieldC k k' x x' | k x' -> k', k' x -> k, k -> x, k' -> x' where
fieldC :: Functor f => (x -> f x') -> k -> f k'
instance (b ~ b0, b' ~ b0') => FieldC (X1 a b) (X1 a b') b0 b0' where ...
instance (b ~ b0, b' ~ b0') => FieldC (X2 c a b) (X2 c a b') b0 b0' where ...
Anda mendefinisikan instance dengan cara yang hampir sama; perhatikan bahwa beberapa batasan kesetaraan ditempatkan dalam konteks untuk meningkatkan inferensi tipe. Anda dapat membaca contoh pertama di atas sebagai instance FieldC (X1 a b) (X1 a b') b b'
.
Kelas untuk bidang lain didefinisikan dengan cara yang persis sama; ini pada dasarnya adalah cara paling umum untuk mendefinisikan kelas lensa (yang akan lebih jelas jika diketahui bahwa tipe fieldC
sebenarnya hanya Lens k k' x x'
).
class FieldA k k' x x' | k x' -> k', k' x -> k, k -> x, k' -> x' where
fieldA :: Functor f => (x -> f x') -> k -> f k'
class FieldB k k' x x' | k x' -> k', k' x -> k, k -> x, k' -> x' where
fieldB :: Functor f => (x -> f x') -> k -> f k'
(Catatan: ini juga dapat digeneralisasikan ke satu kelas dengan parameter tambahan yang sesuai dengan nama bidang; ini mungkin di luar cakupan pertanyaan ini).
Sekarang seharusnya lebih jelas cara menulis deklarasi instance:
instance (x0 ~ Int, x1 ~ Int) => FieldB (X1 a c) (X1 a c) x0 x1 where ...
instance (b0 ~ b, b0' ~ b') => FieldB (X2 a b c) (X2 a b' c) b0 b0' where ...
instance (a ~ a0, a' ~ a0') => FieldA (X1 a c) (X1 a' c) a0 a0' where ...
instance (a0 ~ a, a0' ~ a') => FieldA (X2 a b c) (X2 a' b c) a0 a0' where ...
Satu-satunya perbedaan untuk bidang monomorfik adalah bahwa tipe bidangnya adalah tipe monomorfik.
Tes sederhana akan menunjukkan bahwa tipe polimorfik yang tepat telah ditetapkan:
foo x =
let y = view fieldB x
in set fieldA (2 * y) $ set fieldC (3 + y) x
Anda dapat menanyakan tipe yang disimpulkan pada GHCI pada contoh tertentu:
\x -> foo x `asTypeOf` X1{} :: X1 a b -> X1 Int Int
\x -> foo x `asTypeOf` X2{} :: Num a0' => X2 a a0' b -> X2 a0' a0' a0'
Pola umum ini dapat ditemukan diterapkan misalnya. di sini. Penerapan ini sedikit lebih permisif; f
di Functor f => ..
adalah parameter kelas tipe alih-alih diukur secara universal. Bergantung pada kasus penggunaan spesifik Anda, ini mungkin berhasil atau tidak.
person
user2407038
schedule
13.11.2017