访问 Haskell 中的 "default show"?
Accessing the "default show" in Haskell?
假设你有一个数据结构(从这个 question 借来的):
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"
对于这个当然可行的小例子。但是如果选项的个数比较长,工作量就大了。
我想知道是否可以访问 "default show" 实现并使用通配符调用它。例如:
instance Show Greek where
show (Number x) = show x
show x = defaultShow x
您因此 "implement" 与默认方法不同的特定模式和其余模式由 "fallback mechanism" 解决。
有点类似于面向对象编程中对 super.method
的方法覆盖。
不,据我所知这不可能。
此外,Show
的自定义实例值得重新考虑,因为 Show
和 Read
实例应该相互兼容。
如果只是转换为人类(或任何人)可读的字符串,请使用您自己的函数或您自己的类型类。这也将实现你想要的:
假设你有一个 Presentable
带有方法 present
的类型类,还有默认的 Show
实例,你可以这样写:
instance Presentable Greek where
present (Number x) = show x
present x = show x
您可以使用 Data 和 Typeable 完成此操作。这当然是一个黑客,这个例子只适用于 "enumerated" 类型,就像你的例子一样。
我相信我们可以更详细地说明我们是如何做到这一点的,但为了涵盖您给出的示例:
{-# 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
我实现的这种方法不能处理嵌套数据结构或任何其他远程奇特的东西,但同样,这是一个丑陋的 hack。如果你真的 必须 使用这种方法,你可以在 Data.Data
包中挖掘我相信你可以拼凑一些东西......
这里有一篇博客 post 对软件包进行了快速介绍: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)
正如@phg 在评论中指出的那样,这也可以在 generic-deriving:
的帮助下完成
{-# 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
假设你有一个数据结构(从这个 question 借来的):
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"
对于这个当然可行的小例子。但是如果选项的个数比较长,工作量就大了。
我想知道是否可以访问 "default show" 实现并使用通配符调用它。例如:
instance Show Greek where
show (Number x) = show x
show x = defaultShow x
您因此 "implement" 与默认方法不同的特定模式和其余模式由 "fallback mechanism" 解决。
有点类似于面向对象编程中对 super.method
的方法覆盖。
不,据我所知这不可能。
此外,Show
的自定义实例值得重新考虑,因为 Show
和 Read
实例应该相互兼容。
如果只是转换为人类(或任何人)可读的字符串,请使用您自己的函数或您自己的类型类。这也将实现你想要的:
假设你有一个 Presentable
带有方法 present
的类型类,还有默认的 Show
实例,你可以这样写:
instance Presentable Greek where
present (Number x) = show x
present x = show x
您可以使用 Data 和 Typeable 完成此操作。这当然是一个黑客,这个例子只适用于 "enumerated" 类型,就像你的例子一样。
我相信我们可以更详细地说明我们是如何做到这一点的,但为了涵盖您给出的示例:
{-# 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
我实现的这种方法不能处理嵌套数据结构或任何其他远程奇特的东西,但同样,这是一个丑陋的 hack。如果你真的 必须 使用这种方法,你可以在 Data.Data
包中挖掘我相信你可以拼凑一些东西......
这里有一篇博客 post 对软件包进行了快速介绍: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)
正如@phg 在评论中指出的那样,这也可以在 generic-deriving:
的帮助下完成{-# 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