List instance: Difference between revisions
No edit summary |
Benmachine (talk | contribs) (remove the need for TypeSynonymInstances in the example) |
||
Line 98: | Line 98: | ||
<haskell> | <haskell> | ||
{-# LANGUAGE FlexibleInstances #-} | {-# LANGUAGE FlexibleInstances #-} | ||
instance C | instance C [Char] where toX = ... | ||
</haskell> | </haskell> | ||
Revision as of 14:37, 2 October 2010
Question
How to make a list type an instance of some type class in Haskell 98?
Haskell 98 does not support instances on particular composed types like String
.
If I have a type class for conversion to a type X
:
class C a where
toX :: a -> X
I can define instances for
instance C Int where toX = ...
instance C Double where toX = ...
instance C Tuple where toX = ...
but not for Strings, given that they are a synonym for [Char]
. Hence:
instance C String where toX = ...
results in:
Illegal instance declaration for `C String'
(The instance type must be of form (T a b c)
where T is not a synonym, and a,b,c are distinct type variables)
In the instance declaration for `C String'
Is there some type class cleverness that can make this work in haskell 98? I can create a new wrapper type for strings:
newtype StringWrap = StringWrap String
and write an instance for that, but then I'll have to litter my code with calls to this constructor.
I'm aware of the approach taken by class Show
in the prelude, which
adds a extra method to the class:
class C a where
toX :: a -> X
listToX :: [a] -> X
but I believe this says that whenever we can convert a to an X
we can also
convert [a]
to an X
, whereas I only want [Char]
to be acceptable.
Answer
The trick in the Prelude is that listToX
has a default implementation.
If this is not possible in your application then introduce a new class like
class Element a where
listToX :: [a] -> X
and define instances like
instance Element Char where
listToX = ...
instance Element a => C [a] where
toX = listToX
.
Or more generally, you can introduce a new class like
class IsChar a where
fromChar :: Char -> a
toChar :: a -> Char
instance IsChar Char where
fromChar = id
toChar = id
and then whenever you want to use the "a
" type as a Char
, you just convert it from/to Char
with fromChar
/toChar
as appropriate.
With FlexibleInstances
The -XFlexibleInstances
language extension is designed to solve this problem. See http://www.haskell.org/ghc/docs/6.8-latest/html/users_guide/type-class-extensions.html#instance-rules
{-# LANGUAGE FlexibleInstances #-}
instance C [Char] where toX = ...
Source
http://www.haskell.org/pipermail/haskell-cafe/2007-May/025742.html