Этот ответ является расширением этого комментария , что привело меня к пониманию того, что происходит
В классах типа Haskell это открытый класс, это означаетчто новые экземпляры класса могут быть созданы после объявления.
Это означает, что мы не можем сделать вывод, что NegSucc a
не является членом Peano
, потому что всегда возможно, что он может быть объявлен один позже.
instance Peano (NegSucc a)
Таким образом, когда компилятор видит
instance (Peano a) => Increment a (Succ a)
instance Increment (NegSucc Zero) Zero
, он не может знать, что NegSucc Zero
не будет экземпляром Peano
.Если NegSucc Zero
является экземпляром Peano
, он будет увеличиваться до Zero
и Succ (NegSucc Zero)
, что является конфликтом функциональной зависимости.Поэтому мы должны выбросить ошибку.То же самое относится к
instance (Peano a) => Increment (NegSucc (Succ a)) (NegSucc a)
Здесь (NegSucc (Succ a))
также может быть экземпляром Peano
.
Причина, по которой все выглядит так, будто конфликта нет, заключается в том, что мы неявно предполагаем, чтоне другие случаи Peano
, чем те, о которых мы знаем.Когда я преобразовал один экземпляр в два новых значения, я сделал это предположение формальным.
В новом коде
instance (Peano a) => Increment (Succ a) (Succ (Succ a))
instance Increment Zero (Succ Zero)
невозможно добавить что-либо в существующие классы типов, чтобы вызвать типдля сопоставления нескольких конфликтующих экземпляров.