How to print integer literals in binary or hex in haskell?

前端 未结 8 1183
说谎
说谎 2021-01-30 02:13

How to print integer literals in binary or hex in haskell?

printBinary 5 => \"0101\"

printHex 5 => \"05\"

Which libraries/functions allo

相关标签:
8条回答
  • 2021-01-30 02:38

    The Numeric module includes several functions for showing an Integral type at various bases, including showIntAtBase. Here are some examples of use:

    import Numeric (showHex, showIntAtBase)
    import Data.Char (intToDigit)
    
    putStrLn $ showHex 12 "" -- prints "c"
    putStrLn $ showIntAtBase 2 intToDigit 12 "" -- prints "1100"
    
    0 讨论(0)
  • 2021-01-30 02:50

    Here is a simple, efficient, base-agnostic, Unlicenced implementation:

    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
    

    You have to import Data.Word to use Word8 (which limits the values as much as reasonably possible), and you will often need fromIntegral (if only automatic type conversions were a thing...).

    0 讨论(0)
  • 2021-01-30 02:55

    You may also use printf of the printf package to format your output with c style format descriptors:

    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
    

    Output:

    The value of 65535 in hex is: 0x0000ffff
    The html color code would be: #00FFFF
    The value of 65535 in binary is: 1111111111111111

    0 讨论(0)
  • 2021-01-30 02:57

    You could define your own recursive functions like:

    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
    

    Explanation: As you can see, the toNum function converts a k-based value to decimal, using the given base and a mapping function. The mapping function will map special characters to a decimal value (for ex. A=10, B=11, ... in hex). For binary mapping you could also use a lambda expression like you see in binToDec.

    Whereas the toKBaseVal function is the opposite, converting a decimal to a k-based value. Again we need a mapping function which does the opposite: from a decimal to the corresponding special character of the k-based value.

    As a test you can type:

    binToDec(decToBin 7) = 7
    

    Suppose you want to convert from decimal to octal:

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

    Again, I use just a lambda expression, because the mapping is simple: just int to digit.

    Hope that helps! Good programming!

    0 讨论(0)
  • 2021-01-30 02:58

    Silly solution for one-liner fans:

    (\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
    

    The nucleus of the one-liner is:

    quotRem 247 16
    

    For the sake of clarity, you can, alternatively, put the following in a file:

    #!/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
    

    And execute the script with:

    stack runghc -- DecToHex.hs 247
    

    I used fixed-point operator just so it is an example with fixed-point operator; also because it allowed me to construct the one-liner strictly bottom-up. (Note: bottom-up development is to be discouraged.)

    References: stack script syntax, Command line arguments, fix operator definition.

    recursion haskell hex haskell-stack

    0 讨论(0)
  • 2021-01-30 02:59

    If you import the Numeric and Data.Char modules, you can do this:

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

    This will work for any bases up to 16, since this is all that intToDigit works for. The reason for the extra empty string argument in the examples above is that showIntAtBase returns a function of type ShowS, which will concatenate the display representation onto an existing string.

    0 讨论(0)
提交回复
热议问题