คุณสามารถสรุปคำจำกัดความของคลาส HavingField
ได้ โดยเฉพาะอย่างยิ่ง คุณสามารถแสดงความสัมพันธ์ระหว่างตัวแปรประเภทที่อัปเดตและประเภทเรกคอร์ดโดยใช้การขึ้นต่อกันของฟังก์ชัน ซึ่งจะทำให้ตัวแปรประเภทการอัพเดตเกิดขึ้นในตำแหน่งใดก็ได้ และอนุญาตให้อัปเดตฟิลด์ monomorphic
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 ...
คุณกำหนดอินสแตนซ์ในลักษณะเดียวกันมาก โปรดทราบว่าข้อจำกัดความเท่าเทียมกันบางประการถูกวางไว้ในบริบทเพื่อปรับปรุงการอนุมานประเภท คุณสามารถอ่านตัวอย่างแรกด้านบนเป็น instance FieldC (X1 a b) (X1 a b') b b'
คลาสสำหรับฟิลด์อื่นถูกกำหนดในลักษณะเดียวกันทุกประการ นี่เป็นวิธีทั่วไปที่สุดในการกำหนดคลาสสำหรับเลนส์ (ซึ่งควรจะชัดเจนกว่านี้หากใครสังเกตว่าประเภทของ fieldC
จริงๆ แล้วเป็นเพียง 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'
(หมายเหตุ: สิ่งนี้สามารถสรุปเป็นคลาสเดียวได้เช่นกันโดยมีพารามิเตอร์เพิ่มเติมที่สอดคล้องกับชื่อฟิลด์ นี่อาจอยู่นอกขอบเขตของคำถามนี้)
ตอนนี้ควรชัดเจนยิ่งขึ้นว่าจะเขียนการประกาศอินสแตนซ์อย่างไร:
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 ...
ข้อแตกต่างเพียงอย่างเดียวสำหรับฟิลด์ monomorphic คือประเภทฟิลด์เป็นประเภท monomorphic
การทดสอบอย่างง่ายจะแสดงให้เห็นว่ามีการกำหนดประเภทโพลีมอร์ฟิกที่เหมาะสม:
foo x =
let y = view fieldB x
in set fieldA (2 * y) $ set fieldC (3 + y) x
คุณสามารถขอ GHCi สำหรับประเภทที่อนุมานได้ในอินสแตนซ์เฉพาะ:
\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'
รูปแบบทั่วไปนี้สามารถนำไปใช้ได้เช่น ที่นี่. การใช้งานนี้ได้รับอนุญาตมากกว่าเล็กน้อย f
ใน Functor f => ..
เป็นพารามิเตอร์ประเภทคลาสแทนที่จะถูกวัดปริมาณแบบสากล ขึ้นอยู่กับกรณีการใช้งานเฉพาะของคุณ สิ่งนี้อาจจะใช่หรือไม่ก็ได้สำหรับคุณ
person
user2407038
schedule
13.11.2017