Я пытаюсь найти более элегантный способ написать следующий код.
class C c where
type E c :: * -> *
class C c => A c where
g :: E c a -> E c a
class (C c, A c) => D c where
f :: E c a -> E c a
instance A c => D c where
f = g
Это приводит к ошибке.
Test.hs:58:9:
Could not deduce (E c0 ~ E c)
from the context (A c)
bound by the instance declaration at Test.hs:57:10-19
NB: `E' is a type function, and may not be injective
Expected type: E c a
Actual type: E c0 a
Expected type: E c a -> E c a
Actual type: E c0 a -> E c0 a
In the expression: g
In an equation for `f': f = g
Failed, modules loaded: none.
Мое текущее решение - добавить фиктивную переменную, из которой она может быть получена
какой конкретный C используется.
class C c where
type E c :: * -> *
class C c => A c where
g_inner :: c -> E c a -> E c a
g = g_inner undefined
class (C c, A c) => D c where
f_inner :: c -> E c a -> E c a
f = f_inner undefined
instance A c => D c where
f_inner = g_inner
Я знаю, что это еще один случай, когда ассоциированные типы не являются инъективными,
но я не могу понять это. Конечно, E не может быть инъективным, но это
Кажется где-то информация о том, что g будет работать на конкретном
(E c) ссылка в классе D была потеряна.
Любое объяснение и, что более важно, лучшие обходные пути будут
очень признателен. Спасибо!
редактировать
Хорошо, я вижу, переключение type
на data
заставляет код работать.
Я пытаюсь понять, как это может работать. Каждый c
создает новый тип данных E c
. В контексте экземпляра мы должны сопоставить forall a. ((E) c) a -> ((E) c) a
с forall a. ((E) c) a -> ((E) c) a
. Обозначая F = E c
, мы сопоставляем forall a. F a -> F a
с самим собой.
У меня не получается увидеть, где что-то не так с регистром синонимов типов (связанных типов). Конечно, можно определить два экземпляра A
, каждый из которых имеет подпись (E c) a -> (E c) a
. Но почему было бы неправильно использовать определение из экземпляра A c
, который находится в области видимости?
Спасибо !!