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

僤鯓⒐⒋嵵緔 提交于 2019-12-30 20:40:46

问题


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.

To be convenient and fast, I always show data in hexadecimal e.g.

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

but I want basic types to be showed in hexadecimal (espacially in ghci). I found instance declaration cannot be overridden. and I don't want to warp all of them up like:

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

It looks a little bit stupid.

Can I modify some code in the package base for ghc? I just want everything becoming "hex". I just want ghci showing "hex". how could I achieve it?

EDIT

Since all of us agree that override Show is not proper and impractical, Any answer of "better ways to show Numeric in hexadecimal in ghci" is welcomed.


回答1:


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"



回答2:


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.




回答3:


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.




回答4:


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.



来源:https://stackoverflow.com/questions/9288883/how-to-override-show-instance-of-some-basic-types-in-haskell

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