У меня есть два типа (<->)
и (<-->)
, представляющие изоморфизмы между типами:
data Iso (m :: k -> k -> *) a b = Iso { to :: m a b, from :: m b a }
type (<->) = Iso (->)
infix 0 <->
data (<-->) a b = Iso' { to' :: a -> b, from' :: b -> a }
infix 0 <-->
Единственное различие между ними состоит в том, что (<->)
- это специализация более общего типа.
Я могу coerce
(<-->)
изоморфизмы легко:
coerceIso' :: (Coercible a a', Coercible b b') => (a <--> b) -> (a' <--> b')
coerceIso' = coerce
Но я получаю ошибку, когда пытаюсь сделать то же самое с (<->)
изоморфизмами:
coerceIso :: (Coercible a a', Coercible b b') => (a <-> b) -> (a' <-> b')
coerceIso = coerce
{-
src/Data/Iso.hs:27:13: error:
• Couldn't match type ‘a’ with ‘a'’ arising from a use of ‘coerce’
‘a’ is a rigid type variable bound by
the type signature for:
coerceIso :: forall a a' b b'.
(Coercible a a', Coercible b b') =>
(a <-> b) -> a' <-> b'
at src/Data/Iso.hs:25:1-73
‘a'’ is a rigid type variable bound by
the type signature for:
coerceIso :: forall a a' b b'.
(Coercible a a', Coercible b b') =>
(a <-> b) -> a' <-> b'
at src/Data/Iso.hs:25:1-73
-}
Мой текущий способ обхода заключается в том, чтобы принудительно выполнять функции перемотки вперед и назад:
coerceIso :: (Coercible a a', Coercible b b') => (a <-> b) -> (a' <-> b')
coerceIso (Iso f f') = Iso (coerce f) (coerce f')
Но зачем такой обходной путь необходим? Почему нельзя (<->)
принуждаться напрямую?