TL;DR:
复制前奏的方式并使用showList_作为类函数来生成列表的实例,以便您可以覆盖String的定义。
警告
郑重声明,wowofbob's answer 使用 newtype 包装器是我在现实生活中会使用的简单、干净的解决方案,但我觉得看看 Prelude 如何做到这一点也很有启发性。
默认插入逗号
在前奏中这样做的方式是使Show 类具有显示列表的功能,并具有可以覆盖的默认定义。
import Data.List (intercalate)
我将使用intercalate :: [a] -> [[a]] -> [a] 在内容之间添加逗号:
ghci> intercalate "_._" ["intercalate","works","like","this"]
"intercalate_._works_._like_._this"
创建一个 showList_ 类函数,默认显示和逗号分隔的列表。
所以现在这个类具有showList 函数的默认实现,重要的是,一个默认的show_ 实现只使用普通的show 函数。为了能够使用它,我们必须坚持该类型已经在 Show 类型类中,但据我了解,这没关系。
class Show a => Show_ a where
show_ :: a -> String
showList_ :: [a] -> String
show_ = show
showList_ xs = '[' : intercalate ", " (map show_ xs) ++ "]"
真正的 Show 类出于效率原因直接使用 String -> String 类型的函数而不是 String,并使用优先级参数来控制括号的使用,但为简单起见,我将跳过所有这些。
自动为列表创建实例
现在我们可以使用showList 函数为列表提供一个实例:
instance Show_ a => Show_ [a] where
show_ xs = showList_ xs
Show a => 超类使实例变得超级简单
现在我们来看一些例子。由于我们默认的show_ 实现,我们不需要做任何实际的编程,除非我们想要覆盖默认值,我们将为Char 做这件事,因为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
在实践中:
现在在 ghci 的输出中隐藏 " 并没有多大用处,因为默认的 show 函数用于此目的,但如果我们使用 putStrLn,引号就会消失:
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>