I Я пытаюсь найти более элегантный способ написать следующий код.
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 ] был утерян.
Мы будем очень благодарны за любое объяснение и, что более важно, лучшие обходные пути. Спасибо!
Хорошо, я вижу, что переключение типа
на данные
заставляет код работать.
Я пытаюсь понять, как это может сработать. Каждый c
создает новый тип данных E c
. В контексте экземпляра мы должны сопоставить для всех a. ((E) c) a -> ((E) c) a
с для всех a. ((E) c) a -> ((E) c) a
. Обозначая F = E c
, мы затем сопоставляем для всех a. F a -> F a
с самим собой.
Мне трудно увидеть, где что-то ломается из-за регистра синонимов типов (связанных типов). Конечно, можно определить два экземпляра A
, оба из которых имеют сигнатуру (E c) a -> (E c) a
. Но почему было бы неправильно использовать определение из экземпляра A c
, который входит в область действия?
Спасибо !!