As an exercise, I am implementing in Haskell a ‘cons’ operation that forms a pair from two values of any type. Implementing the needed data type is easy enough:
data Nil = Nil deriving (Eq)
data Pair a b = Cons a b deriving (Eq)
car (Cons x _) = x
cdr (Cons _ y) = y
caar = car . car
cdar = cdr . car
cadr = car . cdr
cddr = cdr . cdr
*Main> cddr (Cons 55 (Cons (1,2,3,4) "hello, world!"))
"hello, world!"
*Main>
but inspired by this thread, I want to make the resulting pairs print out like Scheme lists would – including the infamous “improper list” (1 2 3 . 4). My implementation (see below) is working for Char’s:
*Main> Cons 'a' (Cons 'b' (Cons 'c' Nil))
('a' 'b' 'c')
*Main> Cons 'a' (Cons 'b' 'c')
('a' 'b' . 'c')
*Main> Cons (Cons 'a' 'b')(Cons 'c' (Cons 'd' Nil))
(('a' . 'b') 'c' 'd')
It’s not working so well for Int’s (or any other data type). So my question is: how can I make this work for other data types? i.e., I want it to work like this:
*Main> Cons 5 (Cons "hello" (Cons False Nil))
(5 "hello" False)
My current full implementation follows:
data Nil = Nil deriving (Eq)
data Pair a b = Cons a b deriving (Eq)
car (Cons x _) = x
cdr (Cons _ y) = y
caar = car . car
cdar = cdr . car
cadr = car . cdr
cddr = cdr . cdr
instance Show Nil where show _ = "()"
class ShowPair a where
showRight::a->String
instance (Show a, ShowPair a, ShowPair b)=>Show (Pair a b) where
show (Cons car cdr) = "(" ++ (show car) ++ (showRight cdr) ++ ")"
instance (Show a, ShowPair a, ShowPair b)=>ShowPair (Pair a b) where
showRight (Cons car cdr) = " " ++ (show car) ++ (showRight cdr)
instance ShowPair Char where
showRight x = " . " ++ show x
instance ShowPair Int where
showRight x = " . " ++ show x
instance ShowPair Nil where
showRight _ = ""
Here’s an option. First, enable these extensions by putting this line at the top of your file:
Next, remove your
ShowPairinstances forCharandInt.Now add a
ShowPairinstance for anything withShow:This now ensures that any type
awhich is an instance ofShowis also an instance ofShowPairwhere it is shown by prepending a.to its normal string form. However, if a type has a more specificShowPairinstance (e.g.Nil), Haskell will use that one instead.This is not part of standard Haskell, so you need to enable the three language extensions. Look at How to write an instance for all types in another type class? for more information on why you need the extensions.