I'm learning about existential quantification, phantom types, and GADTs at the moment. How do I go about creating a heterogeneous list of a data type with a phantom variable? For example:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ExistentialQuantification #-}
data Toy a where
TBool :: Bool -> Toy Bool
TInt :: Int -> Toy Int
instance Show (Toy a) where
show (TBool b) = "TBool " ++ show b
show (TInt i) = "TInt " ++ show i
bools :: [Toy Bool]
bools = [TBool False, TBool True]
ints :: [Toy Int]
ints = map TInt [0..9]
Having functions like below are OK:
isBool :: Toy a -> Bool
isBool (TBool _) = True
isBool (TInt _) = False
addOne :: Toy Int -> Toy Int
addOne (TInt a) = TInt $ a + 1
However, I would like to be able to declare a heterogeneous list like so:
zeros :: [Toy a]
zeros = [TBool False, TInt 0]
I tried using an empty type class to restrict the type on a by:
class Unify a
instance Unify Bool
instance Unify Int
zeros :: Unify a => [Toy a]
zeros = [TBool False, TInt 0]
But the above would fail to compile. I was able to use existential quantification to do get the following:
data T = forall a. (Forget a, Show a) => T a
instance Show T where
show (T a) = show a
class (Show a) => Forget a
instance Forget (Toy a)
instance Forget T
zeros :: [T]
zeros = [T (TBool False), T (TInt 0)]
But this way, I cannot apply a function that was based on the specific type of a in Toy a to T e.g. addOne above.
In conclusion, what are some ways I can create a heterogeneous list without forgetting/losing the phantom variable?
data Toy = TBool Bool | TInt Int;isBool (TBool _) = True; isBool _ = False,addOne (TInt a) = TInt $ a + 1;zeros = [Toy]; zeros = [TBool False, TInt 0]. Or do you really need that polymorphism there and your actual use case is more complex? - bheklilrdata Sequence = Sequence (Toy Int)where it doesnot apply toToy Bool, and vice versa. And also, in your reply, wouldn't your definition ofaddOnenot total? .i.e. CallingaddOneonTBool bwould cause an error? - gspindlesaddOne (TInt a) = TInt $ a + 1; addOne x = x. - bheklilrnewtype TInt = TInt Int,TBoolsimilarly anddata Toy = ToyInt TInt | ToyBool TBool. So you can haveSequence TInt. I wouldn't use GADTs before they are really necessary, e.g. having constructor likeEqToy :: Toy a -> Toy a -> Toy BoolorMultiToy :: Toy a -> Toy [a]- phadejnewtypeinstead ofdata). But untimately, I wanted to work withToyas the bottom most data where everything else operarates on. Hence the need for the phantom and going out of my way to make it work in higher up composite data/function. I.e. in theSequencedata in reply to @bleklilr, I don't wantSequenceto takeTIntin your example, I want it to take aToy. - gspindles