Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functions to Polymorphic data types

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 Showso I can use getFoo like:

main = getLine >>= (print . getFoo)
like image 851
homam Avatar asked Dec 19 '22 14:12

homam


1 Answers

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
like image 113
Pi Delport Avatar answered Jan 10 '23 15:01

Pi Delport