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

假装没事ソ 提交于 2019-12-01 18:15:11

That would be abusing the Show instance. It's not really meant for formatting. If you want to show something in hexadecimal, just use a function to do the conversion. For example, you can use showHex from Numeric to make a small helper like this:

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

No, there is no way to achieve this without newtypes; instances cannot be overriden.

If you really want this, I would suggest defining your own typeclass, ShowHex, like Show but with all the instances printing in hex. However, I would consider your Show instance incorrect; Show instances are designed for debugging and serialisation, and should output syntactically valid code.1 Yours doesn't, so I would suggest either defining your own typeclass for displaying these values, or simply using a function.

Modifying the code to base for this is impractical; not only would this change in semantics for the instances break a lot of packages, but it'd be a huge pain to get GHC to actually use your modified version.

1 Ideally, the code they produce should be semantically valid Haskell that produces a value comparing equal to show's input, but this is not strictly necessary.

One extreme solution would be to use {-# LANGUAGE NoImplicitPrelude #-}, and import your own "Prelude" instead. That would probably be a lot more work than it's worth for your case, though.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!