Итак, прежде всего, давайте повторим, что экземпляр, который вы хотите получить для вас, это:
instance MyEq (Wrapper Int) Wrapper where
eq (Wrapper t) (Wrapper t') = Wrapper (t == t')
Я не могу найти способ вывести класс именно так, как вы хотите, потому чтокак вы сами наблюдаете, это требует от вас изменения обоих параметров класса, но в настоящее время мы можем получить только последние.
Одна из возможностей состоит в том, чтобы перевернуть аргументы класса, чтобы "важный" параметр класса (тот, которыйкоторый определяет другое) становится последним, а затем настраивает тип обертки, который вы выводите, чтобы включить некоторую полезную информацию, например:
class MyEq f a | a -> f where
aeq :: a -> a -> f Bool
Функция aeq
сохраняет тот же тип, но аргументы классаMyEq
перевернуты.Теперь Wrapper2
получает дополнительный параметр, позволяющий нам указать желаемое значение f
при получении:
newtype Wrapper2 (f :: Type -> Type) t = Wrapper2 t
Теперь экземпляр для Wrapper2
можно определить без явного указания f
:
instance (Eq t, Coercible Bool (f Bool)) => MyEq f (Wrapper2 f t) where
eq (Wrapper2 t) (Wrapper2 t') = coerce (t == t')
Дополнительный параметр в Wrapper2
необходим здесь для удовлетворения функциональной зависимости.
Теперь мы можем получить желаемый экземпляр следующим образом:
deriving via Wrapper2 Wrapper Int instance MyEq Wrapper (Wrapper Int)
Это работаетпотому что теперь GHC ищет instance MyEq Wrapper (Wrapper2 Wrapper Int)
, и это соответствует предоставленному нами.
Вы можете достичь того же, используя связанный тип:
class MyEq a where
type Result a :: Type -> Type
eq :: a -> a -> Result a Bool
То жеопределение Wrapper2
с дополнительным аргументом.Экземпляр становится
instance (Eq t, Coercible Bool (f Bool)) => MyEq (Wrapper2 f t) where
type Result (Wrapper2 f t) = f
eq (Wrapper2) (Wrapper2 t') = coerce (t == t')
deriving via Wrapper2 Wrapper Int instance MyEq (Wrapper Int)