I am trying to compare associated types with existential ones, and wrote following snippet:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE StandaloneDeriving #-}
import Prelude
data App = forall t. Eq t => App { f :: t }
deriving instance Eq App
Type checks barks with:
Couldn't match expected type ‘b’ with actual type ‘b1’ ‘b1’ is a rigid type variable bound by
At first glance the same snippet is provided as a solution on stack overflow earlier.
I found probably related GHC issue, but disabling PolyKinds extension doesn't have any effect and Polysemy plugin either.
GHC 9.2.5 is used.
P.S.
So in practice both approaches don't support deriving.
This isn't a GHC bug: there just isn't a sensible definition of
(==) :: App -> App -> Boolin the first place.Given
a :: Appandb :: App, we know they must be (disregarding bottoms)a = App xfor somex(of some typeXwithEq X) andb = App yfor somey(of some typeYwithEq Y). But because you definedAppexistentially, there's absolutely no reason forxandyto be comparable, since they have different types. Within each typeXandY, you could use theEqmethods. Sox == xmakes sense, and so doesy == y, butx == ydoesn't make sense, since you'd be using(==)at the typeX -> Y -> Bool. Therefore the tentative definitionis considered nonsense, regardless of whether it's generated by
derivingor written by hand. The type error you are getting is, at it's heart, just "you are trying to use(==)on objects of potentially different types."Or, in short, exactly how is the expression
App (5 :: Int) == App ("5" :: String)supposed to evaluate?Perhaps you would like it if objects of different types always compared disequal. Then you need to store type information in
AppusingTypeableorTypeRep. You compare for type equality first, and only upon getting a yes can you compare the values.