I have the following type, which is based on the paper Coroutining folds with hyperfunctions:
newtype Hyper a b = Hyper { invoke :: Hyper b a -> b }
It's contravariant in its first argument and covariant in its second, so it's a profunctor:
instance Profunctor Hyper where
lmap f = go where
go (Hyper h) = Hyper $ \(Hyper k) -> h $ Hyper $ f . k . go
rmap g = go where
go (Hyper h) = Hyper $ \(Hyper k) -> g $ h $ Hyper $ k . go
dimap f g = go where
go (Hyper h) = Hyper $ \(Hyper k) -> g $ h $ Hyper $ f . k . go
I also want to implement the (potentially unsafe) coercion operators:
-- (#.) :: Coercible c b => q b c -> Hyper a b -> Hyper a c
(#.) _ = coerce
-- (.#) :: Coercible b a => Hyper b c -> q a b -> Hyper a c
(.#) = const . coerce
However, when I do so, I get the following error message:
• Reduction stack overflow; size = 201
When simplifying the following type:
Coercible (Hyper a b) (Hyper a c)
Use -freduction-depth=0 to disable this check
(any upper bound you could choose might fail unpredictably with
minor updates to GHC, so disabling the check is recommended if
you're sure that type checking should terminate)
• In the expression: coerce
In an equation for ‘#.’: (#.) _ = coerce
I guess it's trying to verify Coercible (Hyper a b) (Hyper a c)
, which requires Coercible b c
and Coerrcible (Hyper c a) (Hyper b a)
, and the latter requires Coercible (Hyper a b) (Hyper a c)
, but it goes in an endless loop.
Any idea what annotations I'd use to fix this, if any? Or should I just bite the bullet and use unsafeCoerce
?