如何覆盖Haskell中显示某些基本类型的实例?

时间:2012-02-15 06:30:18

标签: haskell override

我正在Haskell中编写一些程序,处理很多基本类型,如Word32 / Word64等。 我使用ghci经常测试函数,在终端中查看结果。

为方便快捷,我总是以十六进制显示数据,例如

data Human = M Int | F Int
instance Show Human where
    show M x = printf "man, age %d" x
    show F x = printf "woman, age %d" x

但我希望基本类型以十六进制显示(特别是在ghci中)。 我发现实例声明无法覆盖。 并且想要将它们全部扭曲为:

newtype MyInt = MyInt Int
instance Show MyInt where
    ...

看起来有点愚蠢。

我可以修改ghc包base中的一些代码吗? 我只想让一切都变成“十六进制”。我只想要ghci显示“hex”。我怎么能实现它?

修改

由于我们所有人都同意覆盖Show不合适且不切实际, 欢迎使用“更好的方法在ghci中以十六进制显示数字”的任何答案。

4 个答案:

答案 0 :(得分:6)

不,没有newtype s就无法实现这一目标;实例无法覆盖。

如果您真的想要这个,我建议您定义自己的类型类ShowHex,如Show,但所有实例都以十六进制打印。但是,我会认为您的Show实例不正确; Show个实例是为调试和序列化而设计的,应该输出语法上有效的代码。 1 你的实例没有,所以我建议你定义自己的类型类来显示这些值,或者只是使用一个功能。

为此修改代码是不切实际的;这种实例的语义变化不仅会破坏很多软件包,而且让GHC真正使用你的修改版本也是一件非常痛苦的事。

1 理想情况下,它们生成的代码应该是语义有效的Haskell,它产生一个比较等于show输入的值,但这不是严格的必要的。

答案 1 :(得分:5)

这会滥用Show实例。它不是真正意义上的格式。如果要以十六进制显示某些内容,只需使用函数进行转换即可。例如,您可以使用showHex中的Numeric来制作这样的小帮手:

> import Numeric
Numeric> let hex x = showHex x ""
Numeric> hex 123456
"1e240"

答案 2 :(得分:2)

一个极端的解决方案是使用{-# LANGUAGE NoImplicitPrelude #-},然后导入您自己的“Prelude”。不过,这可能会比你的案子更有价值。

答案 3 :(得分:1)

同意@ehird和@hammar这可能会被滥用。如果想要一些数字总是显示为十六进制,我认为它是合理的,因为" 0xff"是一个数字的合法表示。所以这个:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module HexNumber where

import Numeric
import Text.Read
import qualified Text.Read.Lex as L

newtype HexInt a = HexInt { int :: a }
  deriving (Eq, Ord, Num, Enum)

instance (Show a, Integral a) => Show (HexInt a) where 
  show hi = "0x" ++ showHex (int hi) ""

instance (Num a) => Read (HexInt a) where
-- Couldn't figure out how to write this instance so just copy/paste from Text.Read
  readPrec     = readNumber convertInt
  readListPrec = readListPrecDefault
  readList     = readListDefault

readNumber :: Num a => (L.Lexeme -> ReadPrec a) -> ReadPrec a
readNumber convert =
  parens
  ( do x <- lexP
      case x of
        L.Symbol "-" -> do y <- lexP
                            n <- convert y
                            return (negate n)

        _   -> convert x
  )

convertInt :: Num a => L.Lexeme -> ReadPrec a
convertInt (L.Number n)
| Just i <- L.numberToInteger n = return (fromInteger i)
convertInt _ = pfail

现在我可以:

> let x = 10 :: HexInt Int
> x
0xa
> x * 2
0x14
> let x = 10 :: HexInt Integer
> x
0xa
> x * 2
0x14
> read "0xa" :: HexInt Int
0xa
> read "10" :: HexInt Int
0xa

这对我使用低级别的东西非常有用。也许我会把它放在Hackage上。