如何在haskell中打印二进制或十六进制的整数文字?

时间:2009-12-24 20:41:28

标签: haskell binary io hex

如何在haskell中打印二进制或十六进制的整数文字?

printBinary 5 => "0101"

printHex 5 => "05"

哪些库/函数允许这样做?

我遇到了Numeric模块及其showIntAtBase函数,但无法正确使用它。

> :t showIntAtBase 

showIntAtBase :: (Integral a) => a -> (Int -> Char) -> a -> String -> String

8 个答案:

答案 0 :(得分:79)

数字模块包含多个基数functions for showing an Integral type,包括showIntAtBase。以下是一些使用示例:

import Numeric (showHex, showIntAtBase)
import Data.Char (intToDigit)

putStrLn $ showHex 12 "" -- prints "c"
putStrLn $ showIntAtBase 2 intToDigit 12 "" -- prints "1100"

答案 1 :(得分:30)

您也可以使用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

答案 2 :(得分:28)

如果您导入NumericData.Char模块,则可以执行以下操作:

showIntAtBase 2 intToDigit 10 "" => "1010"
showIntAtBase 16 intToDigit 1023 "" => "3ff"

这适用于最多16个基数,因为intToDigit适用于所有基数。上面示例中额外空字符串参数的原因是showIntAtBase返回类型ShowS的函数,它将显示表示连接到现有字符串。

答案 3 :(得分:6)

您可以使用以下内容将整数转换为二进制:

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]

答案 4 :(得分:4)

十六进制可以用0x编写,二进制用0b前缀编写,例如:

> 0xff
255
>:set -XBinaryLiterals
> 0b11
3

请注意,二进制文件需要BinaryLiterals扩展名。

答案 5 :(得分:3)

您可以定义自己的递归函数,如:

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中看到的lambda表达式。

toKBaseVal 函数则相反,将小数转换为基于k的值。我们再次需要一个映射函数,它执行相反的操作:从小数到基于k的值的相应特殊字符。

作为测试,您可以输入:

binToDec(decToBin 7) = 7

假设您要从十进制转换为八进制:

-- decimal to octal
decToOct :: Int -> String
decToOct x = toKBaseNum x 8 (\x -> intToDigit(x))

同样,我只使用lambda表达式,因为映射很简单:只是int到数字。

希望有所帮助!好编程!

答案 6 :(得分:3)

单线风扇的傻瓜解决方案:

(\d -> let fix f = let {x = f x} in x in fmap (\n -> "0123456789abcdef" !! n) (fix (\f l n -> if n == 0 then l :: [Int] else let (q, r) = quotRem n 16 in f (r:l) q) [] d)) 247

单线的核是:

quotRem 247 16

为清楚起见,您也可以将以下内容放在文件中:

#!/usr/bin/env stack
{- stack script --resolver lts-12.1 -}
-- file: DecToHex.hs

module Main where

import System.Environment

fix :: (a -> a) -> a
fix f = let {x = f x} in x

ff :: ([Int] -> Int -> [Int]) -> [Int] -> Int -> [Int]
ff = \f l n ->
  if n == 0
  then l
  else
    let (q, r) = quotRem n 16
    in f (r:l) q

decToHex :: Int -> String
decToHex d =
  fmap (\n -> "0123456789abcdef" !! n)
  (fix ff [] d)

main :: IO ()
main =
  getArgs >>=
  putStrLn . show . decToHex . read . head

并执行以下脚本:

stack runghc -- DecToHex.hs 247

我只是使用定点运算符,所以这是定点运算符的一个示例;也因为它使我能够构建严格的自下而上的一线模式。 (注意:不鼓励自下而上的开发。)

参考:stack script syntaxCommand line argumentsfix operator definition

答案 7 :(得分:0)

这是一个简单,高效,与基础无关的Unlicence d实现:

convertToBase :: Word8 -> Integer -> String
convertToBase b n
    | n < 0              = '-' : convertToBase b (-n)
    | n < fromIntegral b = [(['0'..'9'] ++ ['A' .. 'Z']) !! fromIntegral n]
    | otherwise          = let (d, m) = n `divMod` fromIntegral b in convertToBase b d ++ convertToBase b m

您必须import Data.Word使用Word8(这会尽可能合理地限制值),并且您经常需要fromIntegral(如果仅需要进行自动类型转换)。 ..)。