Использование ScopedTypeVariables
здесь не помогает, потому что p
, который вы используете, в любом случае, кажется, не находится в области видимости.Сравните следующие определения:
changeBase (ZqBasic x) = fromIntegral (value (undefined::foobar))
Это дает ту же ошибку, потому что это также создает новую переменную типа.
changeBase (ZqBasic x) = fromIntegral (value (5::p))
Это, однако, дает другую ошибку.Соответствующие биты:
Could not deduce (Num p1) arising from the literal `5'
(snip)
or from (Zq q (ZqBasic q a), Zq p b)
bound by the type signature for
changeBase :: (Zq q (ZqBasic q a), Zq p b) => ZqBasic q a -> b
Это показывает, что p
создается как переменная нового типа.Я предполагаю, что forall
в сигнатуре типа не вносит в область видимости (в реальных объявлениях) переменные типа, которые не являются параметрами типа класса.Однако переводит переменную в область видимости для объявления по умолчанию.
В любом случае, это ни здесь, ни там.
Достаточно легко обойти большинство проблем с необходимостьюдоступ к переменным типа - просто создайте некоторые вспомогательные функции, которые ничего не делают, но позволяют вам манипулировать типами соответствующим образом.Например, такая бессмысленная функция, как эта, будет притворяться, что вызывает в воображении термин с фантомным типом:
zq :: (Zq q a) => a -> q
zq _ = undefined
Это в основном просто дает вам прямой доступ на уровне терминов к функциональной зависимости, так как fundep делает q
однозначно для любого конкретного a
.Конечно, вы не можете получить фактическое значение, но это не главное.Если undefined
беспокоит вас, используйте [] :: [q]
вместо аналогичного эффекта и используйте head
или что угодно только тогда, когда вам нужно.
Теперь вы можете немного обернуть вещи с помощью предложения where
иличто бы принудительно вывести правильные типы:
instance (IntegralAsType q, Integral a) => Zq q (ZqBasic q a) where
changeBase (ZqBasic x) = b
where b = fromIntegral (value (zq b))
Здесь происходит то, что b
- это то, что нам нужно, но нам нужно value
, чтобы увидеть тип p
, который определяетсятипа b
, поэтому, присваивая временному имени результат, мы можем использовать его для получения нужного нам типа.
Во многих случаях вы можете также сделать это без дополнительного определения, но с классами типоввам нужно избегать специального полиморфизма и убедиться, что он не позволяет "рекурсии" вовлекать другие экземпляры.
В соответствующей заметке стандартная библиотечная функция asTypeOf
предназначена именно для этого типа суетыс типами.