19
votes

I have the following problem with Haskell's type system: I am trying to declare a data type and return a list containing elements of this type from a function. Unfortunately, even a minimal testcase such as

data SampleType = SampleTypeConstructor

instance Show SampleType where
    show x = "(SampleType)"

stList :: (Show a) => [a]
stList = [(SampleTypeConstructor)]

main = do {
    putStrLn (show stList)
}

fails with the following error message from both ghc-7.0.2 and ghc-7.1.20110327:

tcase.hs:7:12:
    Could not deduce (a ~ SampleType)
    from the context (Show a)
      bound by the type signature for stList :: Show a => [a]
      at tcase.hs:7:1-34
      `a' is a rigid type variable bound by
          the type signature for stList :: Show a => [a] at tcase.hs:7:1
    In the expression: (SampleTypeConstructor)
    In the expression: [(SampleTypeConstructor)]
    In an equation for `stList': stList = [(SampleTypeConstructor)]
3

3 Answers

21
votes

the offending line is stList :: (Show a) => [a]. You're declaring that stList is a polymorphic list that holds any element which satisfies the show constraint. But stList isn't a polymorphic list! It's a list of SampleTypes. So remove the signature and see what ghci infers, or just give it the correct signature: :: [SampleType].

21
votes
stList :: (Show a) => [a]

is saying that given any Show instance for any type a, you are going return a list of elements of that type.

stList = [SampleTypeConstructor]

is returning list of SampleTypes, while that is a list of elements for which there exists a Show instance, it is not a list that works for every choice of a.

In reality the only inhabitant you are likely to find for this type that doesn't involve bottoms is [], because Show a doesn't provide any mechanism to construct an a.

To fix this you can do one of a few things, depending on your end goal.

You may just want to let stList have the more narrow type:

stList :: [SampleType]

You may want to build some kind of type like

newtype Showable = Showable (Int -> String -> String)

which explicitly captures the relevant portion of the Show instance. (You can also do this with an existential type, but this version is Haskell 98.)

instance Show Showable where
    showsPrec d (Showable f) = f d

showable :: Show a => a -> Showable
showable a = Showable (\d -> showsPrec d a)

Then you could make a list of Showables.

stList :: [Showable]
stList = [showable SampleTypeConstructor]

But ultimately it depends on what you are trying to accomplish.

1
votes

Haskell does support heterogenous lists of elements, provided their elements are correctly wrapped (see live code on repl.it):

{-# LANGUAGE GADTs #-}

-- your sample type
data SampleType = SampleConstructor

instance Show SampleType where
  show _ = "(SampleType)"

-- MkShowable wrapper
data Showable where
  MkShowable :: Show a => a -> Showable

instance Show Showable where
  show (MkShowable a) = show a


main = do
  let myList :: [Showable]
      myList = [MkShowable SampleConstructor, MkShowable 1, MkShowable True]
  putStrLn $ show myList
  -- ["(SampleType)","1","True"]

See Heterogenous collections for more options.