我尝试在show
上编写一个变体,通过不包括"来对待字符串与Show
的其他实例不同。并直接返回字符串。但我不知道该怎么做。模式匹配?逆天?我在任何文档中都找不到任何相关内容。
这是我尝试过的,没有编译的内容:
show_ :: Show a => a -> String
show_ (x :: String) = x
show_ x = show x
答案 0 :(得分:5)
如果可能,您应该将String
类型的值包装在newtype
中,如@wowofbob所示。
然而,有时这是不可行的,在这种情况下,有两种通用的方法可以使某些内容专门识别String
。
第一种方法,即自然的Haskell方法,是使用类似Show
的类型类来获得不同类型的不同行为。所以你可以写
class Show_ a where
show_ :: a -> String
然后
instance Show_ String where
show_ x = x
instance Show_ Int where
show_ x = show x
等您要使用的任何其他类型。这样做的缺点是您需要为所需的所有类型明确写出Show_
个实例。
@AndrewC展示了如何将每个实例剪切成一行,但您仍然必须明确地列出它们。理论上可以解决这个问题,详见this question,但这并不令人愉快。
第二个选项是使用Typeable
类获取真实的运行时类型信息,这在这种特殊情况下非常简短:
import Data.Typeable
[...]
show_ :: (Typeable a, Show a) => a -> String
show_ x =
case cast x :: Maybe String of
Just s -> s
Nothing -> show x
这不是一种自然的Haskell-ish方法,因为它意味着调用者无法详细说明该函数将从该类型中做什么。
类型类通常给出约束多态性,因为特定函数行为的唯一变化必须来自相关类型类实例中的变体。 Show_
类从其名称中给出了一些指示,并且可能会记录在案。
然而Typeable
是一个非常普通的类。您将所有内容委托给您正在调用的特定功能;具有Typeable
约束的函数可能对许多不同的具体类型具有完全不同的实现。
最后,对Typeable
解决方案的进一步阐述更接近您的原始代码是使用几个扩展:
{-# LANGUAGE ViewPatterns, ScopedTypeVariables #-}
import Data.Typeable
[...]
show_ :: (Typeable a, Show a) => a -> String
show_ (cast -> Just (s :: String)) = s
show_ x = show x
使用ViewPatterns
允许我们在模式中编写cast
,这可能更适合更复杂的示例。实际上,我们可以省略:: String
类型约束,因为此案例的正文强制s
成为show_
的结果类型,即String
。但这有点模糊,所以我认为最好是明确的。
答案 1 :(得分:4)
您可以将其打包到newtype
并为其创建自定义Show
实例:
newtype PrettyString = PrettyString { toString :: String }
instance Show PrettyString where
show (PrettyString s) = "$$" ++ s ++ "$$" -- for example
然后像下面这样使用它:
main = getLine >>= print . PrettyString
答案 2 :(得分:2)
<强> TL; DR:强>
复制前奏的方法并使用showList_
作为类函数来生成列表实例,以便您可以覆盖String的定义。
<强>买者强>
为了记录,使用newtype包装器的wowofbob's answer是我在现实生活中使用的简单,干净的解决方案,但我觉得看看Prelude如何做到这一点是有益的。
默认隐藏逗号
在前奏中完成此操作的方法是使Show
类具有显示列表的功能,并使用您可以覆盖的默认定义。
import Data.List (intercalate)
我会使用intercalate :: [a] -> [[a]] -> [a]
在逗号之间插入逗号:
ghci> intercalate "_._" ["intercalate","works","like","this"]
"intercalate_._works_._like_._this"
现在,该类具有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>