Как переопределить Показать экземпляр некоторых основных типов в Haskell? - PullRequest
5 голосов
/ 15 февраля 2012

Я пишу некоторые программы на Хаскеле, которые имеют дело с множеством базовых типов, таких как 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
    ...

Это выглядит немного глупо.

Могу ли я изменить код в пакете base для ghc? Я просто хочу, чтобы все стало "гексом". Я просто хочу, чтобы ghci показывал "hex". как я мог достичь этого?

EDIT

Поскольку все мы согласны с тем, что переопределение Шоу не является правильным и непрактичным, Приветствуется любой ответ на вопрос "Лучшие способы показать Числовое в шестнадцатеричном в ghci".

Ответы [ 4 ]

6 голосов
/ 15 февраля 2012

Нет, без newtype s нет способа достичь этого;экземпляры не могут быть переопределены.

Если вы действительно этого хотите, я бы предложил определить ваш собственный класс типов, ShowHex, например Show, но со всеми экземплярами, печатаемыми в шестнадцатеричном формате.Однако я считаю ваш Show экземпляр неправильным;Show Экземпляры предназначены для отладки и сериализации и должны выводить синтаксически правильный код. 1 Ваш нет, поэтому я бы предложил либо определить собственный класс типов для отображения этих значений, либо просто использовать функцию.

Изменение кода для базы для этого нецелесообразно;не только это изменение семантики для экземпляров нарушит множество пакетов, но было бы очень трудно заставить GHC фактически использовать вашу модифицированную версию.

1 В идеале,код, который они производят, должен быть семантически действительным Haskell, который выдает значение, сравниваемое со значением show, но это не является строго необходимым.

5 голосов
/ 15 февраля 2012

Это будет злоупотреблять экземпляром Show.Это на самом деле не предназначено для форматирования.Если вы хотите показать что-то в шестнадцатеричном формате, просто используйте функцию для преобразования.Например, вы можете использовать showHex из Numeric, чтобы сделать такого маленького помощника:

> import Numeric
Numeric> let hex x = showHex x ""
Numeric> hex 123456
"1e240"
2 голосов
/ 15 февраля 2012

Одним из крайних решений было бы использование {-# LANGUAGE NoImplicitPrelude #-} и импорт вместо него собственной «Prelude».Это, вероятно, будет гораздо больше работы, чем это стоит для вашего случая.

1 голос
/ 06 ноября 2014

Согласиться с @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

Мне кажется, это очень полезно для работы с вещами низкого уровня. Может быть, я положу это на Хакейдж.

...