Как классы типов вписываются в эту модель?
Короткий ответ: они этого не делают.
Всякий раз, когда вы вводите в язык принуждения, классы типов или другие механизмы для специального полиморфизма, основной проблемой проектирования, с которой вы сталкиваетесь, является согласованность .
По сути, вам нужно убедиться, что разрешение класса типов является детерминированным, чтобы у хорошо типизированной программы была единственная интерпретация. Например, если бы вы могли дать несколько экземпляров для одного и того же типа в одной и той же области, вы могли бы потенциально написать неоднозначные программы, подобные этой:
class Blah a where
blah : a -> String
instance Blah T where
blah _ = "Hello"
instance Blah T where
blah _ = "Goodbye"
v :: T = ...
main :: IO ()
main = print (blah v) -- does this print "Hello" or "Goodbye"?
В зависимости от выбора экземпляра, который делает компилятор, blah v
может равняться либо либо, "Hello"
либо "Goodbye"
. Следовательно, смысл программы не будет полностью определяться синтаксисом программы, а скорее может зависеть от произвольного выбора, который делает компилятор.
Решение этой проблемы в Haskell состоит в том, чтобы каждый тип имел не более одного экземпляра для каждого класса типов. Чтобы обеспечить это, он разрешает объявления экземпляров только на верхнем уровне и, кроме того, делает все объявления глобально видимыми. Таким образом, компилятор всегда может сообщить об ошибке, если сделано неоднозначное объявление экземпляра.
Однако объявление глобально видимым нарушает композиционную семантику. Что вы можете сделать для восстановления, так это дать семантику разработки для языка программирования - то есть вы можете показать, как переводить программы на Haskell в язык с хорошим поведением и композиционным языком.
На самом деле это также дает вам возможность компилировать классы типов - обычно это называется «преобразованием доказательств» или «преобразованием словаря» в кругах Haskell и является одним из ранних этапов большинства компиляторов Haskell.
Классы типов также являются хорошим примером того, как дизайн языка программирования отличается от теории чистого типа. Классы типов - действительно потрясающая особенность языка, но они довольно плохо себя ведут с точки зрения теории доказательств. (Вот почему Agda вообще не имеет классов типов и почему Coq делает их частью своей инфраструктуры эвристического вывода.)