Lists of data types: "could not deduce (a ~ SomeType) from the context (SomeTypeclass a)"
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)]
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 SampleType
s. So remove the signature and see what ghci infers, or just give it the correct signature: :: [SampleType]
.
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 SampleType
s, 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.
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.
精彩评论