How to override Show instance of some basic types in Haskell?

后端 未结 4 1396
太阳男子
太阳男子 2021-01-18 05:19

I\'m writting some programs in Haskell, dealing with a lot of basic types like Word32/Word64 etc.. I use ghci to test the functions frequently, see the results in terminal.<

4条回答
  •  清歌不尽
    2021-01-18 05:52

    Agreeing with @ehird and @hammar that this could be abused. In the case of wanting some numbers to always show as hex, I think it's reasonable because "0xff" is a legitimate representation of a number. So this:

    {-# 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
    

    Now I can:

    > 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
    

    This seems very useful to me working with low-level stuff a lot. Maybe I'll put it on Hackage.

提交回复
热议问题