2

I'm aware that with Data.Bits I can do bitwise manipulation on anything with an instance of Bits. That however is not what I want. I explicitly want to manipulate a list of Bools which represent the bit value at each bit index.

More precisely I want to manipulate the bits of a 1-byte integer.

I have managed to get this to work using map/testBit and foldl'/setBit. Which you can see from my tests in ghci below:

λ import Data.Bits
λ import Data.List

λ let convertToBits :: Int -> [Bool] ; convertToBits x = map (testBit x) [7,6..0]

λ let convertFromBits :: [Bool] -> Int ; 
   convertFromBits bs = foldl' (\acc (i,b) -> if b then setBit acc i else acc) 0 $ zip [7,6..0] bs

λ convertToBits 255
[True,True,True,True,True,True,True,True]

λ convertToBits 2
[False,False,False,False,False,False,True,False]

λ convertFromBits [False,False,False,True,True,False,False,True]
25

λ convertFromBits $ convertToBits 255
255

λ convertFromBits $ convertToBits 10
10

However this doesn't feel like a particularly great implementation. I'm wondering if this (or something similar) might be in standard library?

EDIT ------

A quick final note, even though I have answered the question below, I thought I'd add a bit more in case anyone stumbles on this and knows a better answer. I'll be storing all of the bits in a UArray which will bit-pack the Bool values.

In thinking about it, what would be really good is a function that converts a Word8 into a UArray ix Bool. I'd like to think there is some efficient / simple way to do this but I don't know enough about the low level stuff to work it out.

7
  • Word8 certainly seems a more economical choice for this than [Bool] on the surface. Can you say a bit more about why you prefer the latter? Commented Feb 15, 2015 at 3:46
  • It's going to populate a UArray and from what I've read it should bit pack the Bools. Though in their temporary [Bool] state they will take up an unnecessary amount of memory. Reading the bits will trigger the activation of Nodes in a neural network, which will then run its own processing of the inputs. The activated outputs nodes get read as bit values that trigger an Int outputs. Commented Feb 15, 2015 at 3:55
  • Close vote: should be migrated to codereview.stackexchange.com Commented Feb 15, 2015 at 4:27
  • Well I was hoping that there might exist something of the form Word8 -> Array ix Bool or Word8 -> [Bool] that could break a Word8 into its constituent bits in one go (where as my map and fold require 8 steps each). Commented Feb 15, 2015 at 4:33
  • Though that said, having found that snippet from bitwise suggests to me that this is the most practical approach. Assuming there is nothing else than the answer to my question "I'm wondering if this (or something similar) might be in standard library?" is "No". Commented Feb 15, 2015 at 4:35

2 Answers 2

1

This was previously an edit in my question. I would still like to know if there is anything better. I'm imagining something that literally coerces a Word8 into an array of its constituent bits but perhaps that's a bit lofty...

The package bitwise which does a similar implementation to my own but using bitshifting for their fromList function. In lieu of a better idea this suggests that using Data.Bits combined with some sort of map and some sort of fold is the canonical solution:

-- | Convert a little-endian list of bits to 'Bits'.
{-# INLINE fromListLE #-}
fromListLE :: (Num b, Bits b) => [Bool] {- ^ \[least significant bit, ..., most significant bit\] -} -> b
fromListLE = foldr f 0
  where
    f b i = fromBool b .|. (i `shiftL` 1)

-- | Convert a 'Bits' (with a defined 'bitSize') to a list of bits, in
--   little-endian order.
{-# INLINE toListLE #-}
toListLE :: (Num b, Bits b) => b -> [Bool] {- ^ \[least significant bit, ..., most significant bit\] -}
toListLE b = P.map (testBit b) [0 .. bitSize b - 1]
Sign up to request clarification or add additional context in comments.

1 Comment

Or and shift is what I'd use in C, and for bit-level maniputation it's very efficient: I'd expect that iterating over the list (i.e. following pointers) takes much, much more time than the bit operations. With modern superscalar CPU the bit ops could be performed in parallel while the CPU reads the next list element.
0

This isn't thoroughly tested, but it's a proposal for a native implementation.

toBitsBySize :: Int -> Int -> [Bool]
toBitsBySize  0 x = []
toBitsBySize sz 0 = [False | i <- [1..sz]]
toBitsBySize sz x =  if k == 0 
    then False : (toBitsBySize n x) 
    else True  : (toBitsBySize n (x - k*m))
    where n = sz - 1
          m = 2^n
          k = x `div` m

toBits8 = toBitsBySize 8

Some examples:

*Main> toBits8 2
[False,False,False,False,False,False,True,False]
*Main> toBits8 255
[True,True,True,True,True,True,True,True]
*Main> toBits8 129
[True,False,False,False,False,False,False,True]

4 Comments

I'm not necessarily looking for an approach that only uses the prelude. Data.Bits is in base and provides a very clean bitiwse API.
In that case, I do not understand the question. Can you supply a specific criterion you're looking for when you say your current implementation doesn't "feel" like a great implementation? I'm going to vote to close the question under the current description since it seems to better belong at the code review site. I'm happy to revoke the close vote pending more details or possibly answers from others.
Using 2^n at every step looks overkill. I'd expect each step to need O(1) operations only (e.g. x `div` 2 or x*2).
For n <= 8, 2^n takes 3 operations to compute: 2^2 = 2*2, 2^4 = 2^2 * 2^2, 2^8 = 2^4 * 2^4.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.