假设您有一个数据结构(借用了这个问题):
data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
现在,通过在该指令上附加deriving Show
,可以使其成为Show
的实例。
假设我们希望将Number Int
显示为:
instance Show Greek where
show (Number x) = show x
-- ...
问题是必须指定Greek
数据的所有其他部分,如:
show Alpha = "Alpha"
show Beta = "Beta"
对于这个小例子来说,这当然是可行的。但是,如果选择的数量很长,就需要大量的工作。
我想知道是否可以访问"默认显示"实现并使用通配符进行调用。例如:
instance Show Greek where
show (Number x) = show x
show x = defaultShow x
因此,您"实现"了与默认方法不同的特定模式,其余模式由"回退机制"解决。
有点类似于面向对象编程中引用super.method
的方法重写。
正如上面评论中提到的@phg,这也可以在泛型派生的帮助下完成:
{-# LANGUAGE DeriveGeneric #-}
module Main where
import Generics.Deriving.Base (Generic)
import Generics.Deriving.Show (GShow, gshow)
data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
deriving (Generic)
instance GShow Greek
instance Show Greek where
show (Number n) = "n:" ++ show n
show l = gshow l
main :: IO ()
main = do
print (Number 8)
print Alpha
您可以使用Data和Typeable对其进行排序。当然,这是一个破解,这个例子只适用于你的例子中的"枚举"类型。
我相信我们可以更详细地说明我们是如何做到这一点的,但要涵盖你给出的例子:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Typeable
data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
deriving (Data,Typeable)
instance Show Greek where
show Number n = show n
show x = show $ toConstr x
正如我所实现的,这种方法无法处理嵌套的数据结构或任何其他奇特的东西,但同样,这是一个丑陋的破解。如果你真的必须使用这种方法,你可以在Data.Data
包中四处挖掘,我相信你可以拼凑一些东西。。。
下面是一篇博客文章,简要介绍了这些软件包:http://chrisdone.com/posts/data-typeable
实现这一点的正确方法是使用newtype
包装器。我意识到这不是最方便的解决方案,尤其是在使用GHCi时,但它不会产生额外的开销,而且随着程序的增长,它不太可能以意外的方式中断。
data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
deriving (Show)
newtype SpecialPrint = SpecialPrint Greek
instance Show SpecialPrint where
show (SpecialPrint (Number x)) = "Number: " ++ show x
show (SpecialPrint x) = show x
main = do
print (SpecialPrint Alpha)
print (SpecialPrint $ Number 1)
不,这是不可能的AFAIK。
此外,Show
的自定义实例值得重新考虑,因为Show
和Read
实例应该相互兼容。
要转换为人类(或任何人)可读的字符串,请使用您自己的函数或类型类。这也将实现您想要的:
假设您有一个方法为present
的Presentable
类型类,以及默认的Show
实例,那么您可以编写:
instance Presentable Greek where
present (Number x) = show x
present x = show x