Как печатать целые литералы в двоичном или шестнадцатеричном виде в haskell?
Как печатать целые литералы в двоичном или шестнадцатеричном формате в haskell?
printBinary 5 => "0101"
printHex 5 => "05"
Какие библиотеки/функции разрешают это?
Я столкнулся с модулем Numeric и его функцией showIntAtBase, но не смог правильно его использовать.
> :t showIntAtBase
showIntAtBase :: (Integral a) => a -> (Int -> Char) -> a -> String -> String
Ответы
Ответ 1
Цифровой модуль включает несколько функций для отображения типа Integral на разных основаниях, включая showIntAtBase
. Вот несколько примеров использования:
import Numeric (showHex, showIntAtBase)
import Data.Char (intToDigit)
putStrLn $ showHex 12 "" -- prints "c"
putStrLn $ showIntAtBase 2 intToDigit 12 "" -- prints "1100"
Ответ 2
Если вы импортируете модули Numeric
и Data.Char
, вы можете сделать это:
showIntAtBase 2 intToDigit 10 "" => "1010"
showIntAtBase 16 intToDigit 1023 "" => "3ff"
Это будет работать для любых баз до 16, поскольку это все, что работает intToDigit
. Причина лишнего пустого аргумента строки в приведенных выше примерах заключается в том, что showIntAtBase
возвращает функцию типа ShowS
, которая объединяет представление отображения в существующую строку.
Ответ 3
Вы также можете использовать printf пакета printf для форматирования вывода с помощью дескрипторов формата c:
import Text.Printf
main = do
let i = 65535 :: Int
putStrLn $ printf "The value of %d in hex is: 0x%08x" i i
putStrLn $ printf "The html color code would be: #%06X" i
putStrLn $ printf "The value of %d in binary is: %b" i i
Вывод:
Значение 65535 в шестнадцатеричном формате: 0x0000ffff
Цветовой код html будет выглядеть так: # 00FFFF
Значение 65535 в двоичном формате: 1111111111111111
Ответ 4
Hex может быть записан с помощью 0x
и двоичным с префиксом 0b
, например:
> 0xff
255
>:set -XBinaryLiterals
> 0b11
3
Обратите внимание, что для двоичного файла требуется расширение BinaryLiterals
.
Ответ 5
Вы можете преобразовать целое число в двоичное с чем-то вроде следующего:
decToBin x = reverse $ decToBin' x
where
decToBin' 0 = []
decToBin' y = let (a,b) = quotRem y 2 in [b] ++ decToBin' a
в GHCi:
Prelude> decToBin 10
[1,0,1,0]
Ответ 6
Вы можете определить свои собственные рекурсивные функции, например:
import Data.Char (digitToInt)
import Data.Char (intToDigit)
-- generic function from base to decimal
toNum :: [Char] -> Int -> (Char -> Int) -> Int
toNum [] base map = 0
toNum s base map = base * toNum (init(s)) base map + map(last(s))
-- generic function from decimal to base k
toKBaseNum :: Int -> Int -> (Int -> Char) -> [Char]
toKBaseNum x base map | x < base = [map x]
| otherwise = toKBaseNum (x `div` base) base map ++ [map(x `mod` base)]
-- mapping function for hex to decimal
mapHexToDec :: Char -> Int
mapHexToDec x | x == 'A' = 10
| x == 'B' = 11
| x == 'C' = 12
| x == 'D' = 13
| x == 'E' = 14
| x == 'F' = 15
| otherwise = digitToInt(x) :: Int
-- map decimal to hex
mapDecToHex :: Int -> Char
mapDecToHex x | x < 10 = intToDigit(x)
| x == 10 = 'A'
| x == 11 = 'B'
| x == 12 = 'C'
| x == 13 = 'D'
| x == 14 = 'E'
| x == 15 = 'F'
-- hex to decimal
hexToDec :: String -> Int
hexToDec [] = 0
hexToDec s = toNum s 16 mapHexToDec
-- binary to decimal
binToDec :: String -> Int
binToDec [] = 0
binToDec s = toNum s 2 (\x -> if x == '0' then 0 else 1)
-- decimal to binary
decToBin :: Int -> String
decToBin x = toKBaseNum x 2 (\x -> if x == 1 then '1' else '0')
-- decimal to hex
decToHex :: Int -> String
decToHex x = toKBaseNum x 16 mapDecToHex
Объяснение:
Как вы можете видеть, функция toNum преобразует значение k в десятичное значение, используя данную базу и функцию отображения. Функция сопоставления отображает специальные символы в десятичное значение (например, A = 10, B = 11,... в шестнадцатеричном виде). Для двоичного отображения вы также можете использовать выражение лямбда, как вы видите в binToDec.
В то время как функция toKBaseVal противоположна, преобразование десятичного числа в значение k. Опять же нам нужна функция отображения, которая делает обратное: от десятичной до соответствующего специального символа значения k.
В качестве теста вы можете ввести:
binToDec(decToBin 7) = 7
Предположим, что вы хотите конвертировать из десятичного в восьмеричный:
-- decimal to octal
decToOct :: Int -> String
decToOct x = toKBaseNum x 8 (\x -> intToDigit(x))
Опять же, я использую только лямбда-выражение, потому что отображение прост: просто int в цифру.
Надеюсь, что это поможет! Хорошее программирование!