data Foo a
is defined like:
data Foo a where
Foo :: (Typeable a, Show a) => a -> Foo a
-- perhaps more constructors
instance Show a => Show (Foo a) where
show (Foo a) = show a
with some instances:
fiveFoo :: Foo Int
fiveFoo = Foo 5
falseFoo :: Foo Bool
falseFoo = Foo False
How can I define any function from b -> Foo a
, for example:
getFoo :: (Show a, Typeable a) => String -> Foo a
getFoo "five" = fiveFoo
getFoo "false" = falseFoo
Here getFoo
does not type check with Couldn't match type ‘a’ with ‘Bool’
.
The only thing that I am interested in here is for a
to be of class Show
so I can use getFoo
like:
main = getLine >>= (print . getFoo)
You can use existential types to make a data type hide and "carry" a type class like Show
around.
Note that using existential types like this is considered to be an anti-pattern in Haskell, and you probably want to consider carefully whether you really want to do this: being more explicit about your types is usually simpler, better, and less prone to bugs.
However, that being said, if you really want to do this, here is how you would use existential types with your example:
{-# LANGUAGE ExistentialQuantification #-}
-- This Foo can only be constructed with instances of Show as its argument.
data Foo = forall a. Show a => Foo a
-- Note that there is no "Show a => ..." context here:
-- Foo itself already carries that constraint around with it.
instance Show Foo where
show (Foo a) = show a
getFoo :: String -> Foo
getFoo "five" = Foo 5
getFoo "false" = Foo False
main = print . getFoo =<< getLine
Demonstration:
ghci> main
five
5
ghci> main
false
False
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With