2 ms·
I mean, I agree such examples exist. I don't think this is yet a truly good example, though. The real advantage to existential types like this are in creation o
by tel 13y ago
I mean, I agree such examples exist. I don't think this is yet a truly good example, though. The real advantage to existential types like this are in creation of multiple variants---again I recommend reading Jeremy Gibbons' paper.
But, for completeness, here's how you could write your type
{-# LANGUAGE ExistentialQuantification #-}
data Test = forall i o . Test i (i -> o) (o -> o -> Bool) o
Although, note, this is exactly equivalent to `Bool`, although in two ways—if we knew the comparator function was commutative then there'd be just one way to convert to `Bool`.
testBool :: Test -> Bool
testBool (Test i fun cmp o) = cmp (fun i) o
testBool' :: Test -> Bool
testBool' (Test i fun cmp o) = cmp o (fun i)
But in either case there are no other ways to "observe" the existentially quantified types since we've forgotten absolutely everything besides `Bool`. More likely we would want to also, say, show the input.
data Test = forall i o . (Eq o, Show i) =>
Test i (i -> o) o
and this type is now equal to `(String, Bool)`.
testOff :: Test -> (String, Bool)
testOff (Test i fun o) = (show i, fun i == o)
So, in general, if you're using existential types you really want to either be using multiple variants or when you have such a combination of observables that it's not worth expressing them all directly.