TL;DR:
Copy the prelude's way and use showList_
as a class function to generate instances for lists so you can override the definition for String.
Caveat
For the record, wowofbob's answer using a newtype wrapper is the simple, clean solution I would use in real life, but I felt it was instructive to also look at some of how the Prelude does this.
intercalate commas by default
The way this is done in the prelude is to make the Show
class have a function for showing lists, with a default definition that you can override.
import Data.List (intercalate)
I'll use intercalate :: [a] -> [[a]] -> [a]
to put commas in between stuff:
ghci> intercalate "_._" ["intercalate","works","like","this"]
"intercalate_._works_._like_._this"
Make a showList_ class function, and default to show and comma-separated lists.
So now the class with the default implementation of the showList
function and, importantly, a default show_
implementation that just uses the ordinary show
function. To be able to use that, we have to insist that the type is already in the Show
typeclass, but that's OK as far as I understand you.
class Show a => Show_ a where
show_ :: a -> String
showList_ :: [a] -> String
show_ = show
showList_ xs = '[' : intercalate ", " (map show_ xs) ++ "]"
The real Show class uses functions of type String -> String
instead of String
directly for efficiency reasons, and a precedence argument to control the use of brackets, but I'll skip all that for simplicity.
Automatically make instances for lists
Now we can use the showList
function to provide an instance for lists:
instance Show_ a => Show_ [a] where
show_ xs = showList_ xs
The Show a =>
superclass makes instances super-easy
Now we come to some instances. Because of our default show_
implementation, we don't need to do any actual programming unless we want to override the default, which we'll do for Char, because String ~ [Char]
.
instance Show_ Int
instance Show_ Integer
instance Show_ Double
instance Show_ Char where
show_ c = [c] -- so show_ 'd' = "d". You can put show_ = show if you want "'d'"
showList_ = id -- just return the string
In practice:
Now that's not much use to hide "
from your output in ghci, because the default show
function is used for that, but if we use putStrLn
, the quotes disappear:
put :: Show_ a => a -> IO ()
put = putStrLn . show_
ghci> show "hello"
"\"hello\""
ghci> show_ "hello"
"hello"
ghci> put "hello"
hello
ghci> put [2,3,4]
[2, 3, 4]
ghci>