Is there a convenient way to get an instance of Ord
(or Eq
) to compare any two values of a GADT, irrespective of the type parameter.
In the GADT, the type parameter is phantom, just meant to associate each constructor with a type, e.g. the GADT represent keys/queries, and the type parameter is the type of the associated value/result.
To illustrate:
{-# LANGUAGE GADTs, Rank2Types #-}
data Car = Car -- whatever
data Food = Food
data CarRental = CarRental {passengers :: Int, mileage :: Int}
deriving (Eq, Ord)
data ErrandList = ErrandList {avoidJunkFood :: Bool}
deriving (Eq, Ord)
data GetStuff a where
RentACar :: CarRental -> GetStuff Car
BuyFood :: ErrandList -> GetStuff Food
data Some t = forall a. Some (t a)
GetStuff
is a GADT, so that each item is associated with a result type, Car
or Food
. I can use that in e.g Free
or FreeApplicative
. I may want to retrieve all the GetStuff that appear in the structure. I can easily build [Some GetStuff]
, but not a Set (Some GetStuff)
, for lack of an Ord instance.
I see that
data GetSomeStuff = RentSomeCar CarRental | BuySomeFood ErrandList
deriving (Eq, Ord)
is isomorphic to Some GetStuff
(a
is phantom in GetStuff), so I can get Eq, Ord, and possibly others by writing this isomorphism:
existentialToUntyped :: Some GetStuff -> GetSomeStuff
untypedToExistential :: GetSomeStuff -> Some GetStuff
untypedToExistential (RentSomeCar x) = Some $ RentACar x
untypedToExistential (BuySomeFood x) = Some $ BuyFood x
existentialToUntyped (Some (RentACar x)) = RentSomeCar x
existentialToUntyped (Some (BuyFood x)) = BuySomeFood x
but it's tedious for protocols much larger than GetStuff. Is there a better way, with or without GADT?
Also, I intend to write code parametric in the "protocol" type (here GetStuff) at this point, where I would like a signature such as
queries :: SomeConstraint protocol =>
FreeApplicative protocol
-> Set (Some protocol)
I may have to do
myFunction :: Ord untyped =>
Iso (Some protocol, untyped)
-> FreeApplicative protocol
-> Set untyped
Again, is there a better way?
GetSomeStuff
is only isomorphic tosigma a. GetStuff a
(a type which doesn’t exist in Haskell). In particular note that[GetSomeStuff]
and[GetStuff a]
are not isomorphic. Alternatively, consider that no halting function of typeGetSomeStuff -> GetStuff a
exists. – Dan Robertson