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

HaskellBinaryIoHex

Haskell Problem Overview


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

printBinary 5 => "0101"

printHex 5 => "05"

Which libraries/functions allow this?

I came across the Numeric module and its showIntAtBase function but have been unable to use it correctly.

> :t showIntAtBase 

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

Haskell Solutions


Solution 1 - Haskell

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"

Solution 2 - Haskell

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

Solution 3 - Haskell

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.

Solution 4 - Haskell

You can convert integer to binary with something like the following:

decToBin x = reverse $ decToBin' x
  where
    decToBin' 0 = []
    decToBin' y = let (a,b) = quotRem y 2 in [b] ++ decToBin' a

usage in GHCi:

Prelude> decToBin 10
[1,0,1,0]

Solution 5 - Haskell

Hex can be written with 0x and binary with 0b prefix e.g.:

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

Note that binary requires the BinaryLiterals extension.

Solution 6 - Haskell

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!

Solution 7 - Haskell

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.

[tag:recursion] [tag:haskell] [tag:hex] [tag:haskell-stack]

Solution 8 - Haskell

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...).

Solution 9 - Haskell

Using the FiniteBits class:

import Data.Bits (FiniteBits, finiteBitSize, testBit, shiftR)

showBits :: FiniteBits a => a -> String
showBits bits =
  go (finiteBitSize bits - 1) where
    go shift =
      if shift >= 0
        then
          let bit = if testBit (shiftR bits shift) 0 then '1' else '0'
          in bit : go (pred shift)
        else
          ""

Examples:

showBits (4 :: Word8) => "00000100"

showBits (50 :: Int16) => "0000000000110010"

showBits (-127 :: Int32) => "11111111111111111111111110000001"

Solution 10 - Haskell

When working with text, I recommend using the text-show package which includes:

For example, converting an Integer to Text in binary:

{-# LANGUAGE OverloadedStrings #-}

import TextShow (toText)
import TextShow.Data.Integral (showbBin)

toBinary :: Integer -> Text
toBinary n = toText . showbBin

> toBinary 6 == "110"

Perhaps you want to add a Text prefix. Builder allows you to efficiently construct Text; it is a monoid.

toBinaryWithPrefix :: Text -> Integer -> Text
toBinaryWithPrefix prefix n = toText $ fromText prefix <> showbBin n

For more information see the TextShow and TextShow.Data.Integral modules available on Hackage.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTheOneView Question on Stackoverflow
Solution 1 - HaskellChuckView Answer on Stackoverflow
Solution 2 - HaskellMartin LütkeView Answer on Stackoverflow
Solution 3 - HaskellIan RossView Answer on Stackoverflow
Solution 4 - HaskellSajad BahmaniView Answer on Stackoverflow
Solution 5 - HaskellMikkelView Answer on Stackoverflow
Solution 6 - HaskellAlessandro GiusaView Answer on Stackoverflow
Solution 7 - HaskellinkbottleView Answer on Stackoverflow
Solution 8 - HaskellSolomon UckoView Answer on Stackoverflow
Solution 9 - HaskellValmir JuniorView Answer on Stackoverflow
Solution 10 - HaskelldopamaneView Answer on Stackoverflow