У меня есть семейство типов данных, проиндексированных целыми числами уровня типа, и я определяю их как экземпляры некоторого класса типов «кусочно», что вызывает проблемы при попытке получить экземпляры другого класса. Для иллюстрации я выделил проблему следующим образом. Рассмотрим этот код:
{-# LANGUAGE ScopedTypeVariables, TypeSynonymInstances,
FlexibleInstances , UndecidableInstances #-}
data Zero
data Succ n
type One = Succ Zero
type Two = Succ One
type Three = Succ Two
class Nat n where
toInt :: n -> Int
instance Nat Zero where
toInt _ = 0
instance Nat One where ------------------------- START MODIFY
toInt _ = 1
instance (Nat n) => Nat (Succ (Succ n)) where
toInt _ = 2 + toInt (undefined :: n) --------- END MODIFY
Это небольшая модификация целых чисел уровня типа, определенных в " Развлечения с функциями типов "Киселева, Джонса и Шаня. Компилируется нормально, и toInt
, похоже, работает, как ожидалось. Прямо сейчас Nat
содержит все целые числа Zero
, One
, Two
и так далее.
Однако GHC жалуется после того, как я добавлю следующие строки и перекомпилирую:
class LikeInt n where
likeInt :: n -> Int
instance (Nat n) => LikeInt (Succ n) where
likeInt = toInt
Ошибка: не удалось вывести (Nat (Succ n))
, возникшую в результате использования «toInt
» из контекста (Nat n)
.
Я предполагаю, что когда GHC делает вывод, что toInt
имеет аргумент типа Succ n
, но единственные экземпляры для Nat
- это Zero
, Succ Zero
и (Nat n0) => Succ (Succ n0)
, а Succ n
не соответствует ни одному из них. Это предположение подтверждается успешной компиляцией, когда я заменяю блок MODIFY
исходным
instance (Nat n) => Nat (Succ n) where
toInt _ = 1 + toInt (undefined :: n)
Как мне заставить likeInt
работать так же, как toInt
, даже с измененным блоком? Это важно для моего настоящего проекта.
Nat
? - person András Kovács   schedule 17.07.2015LikeInt
, это терпит неудачу. - person Herng Yi   schedule 18.07.2015