+-- | Gray code is a binary numeral system where two successive numbers

+-- differ in only one bit.

+module Codec.Binary.Gray

+ -- * List functions (for @[Bool]@)

+ binaryToGray, grayToBinary

+ , bitsToBinary, binaryToBits

+import Data.Bits (Bits, testBit, shiftR, clearBit, bitSize, isSigned)

+xor :: Bool -> Bool -> Bool

+xor p q = (p && not q) || (not p && q)

+-- | Takes a list of bits (most significant last) in binary encoding

+-- and converts them to Gray code.

+-- Haupt, R.L. and Haupt, S.E., Practical Genetic Algorithms,

+-- Second ed. (2004), 5.4. Gray Codes.

+binaryToGray :: [Bool] -> [Bool]

+binaryToGray (b:c:bs) = b `xor` c : binaryToGray (c:bs)

+-- | Takes a list of bits in Gray code and converts them to binary encoding

+-- (most significant bit last).

+-- Haupt, R.L. and Haupt, S.E., Practical Genetic Algorithms,

+-- Second ed. (2004), 5.4. Gray Codes.

+grayToBinary :: [Bool] -> [Bool]

+grayToBinary = foldr go []

+ go c bs@(b:_) = b `xor` c : bs

+-- | Convert a number to a list of bits in usual binary encoding (most

+-- As 'bitSize', 'bitsToBinary' is undefined for types that do not

+-- have fixed bitsize, like 'Integer'.

+bitsToBinary :: (Bits b) => b -> [Bool]

+ let b = map not . bitsToBinary $ negate i - 1

+ in b ++ (take (bitSize i - length b) $ repeat True) -- pad major bits

+ let rest = bitsToBinary $ shiftR i 1 -- works only for positive i

+ in (testBit i 0 : rest)

+-- | Convert a list of bits in binary encoding to a number.

+binaryToBits :: (Bits a) => [Bool] -> a

+binaryToBits = sum . map fst . filter snd . zip (map (2^) [0..])

+-- | Render a list of bits as a 0-1 string.

+showBinary :: [Bool] -> String

+showBinary bs = map (\b -> if b then '1' else '0') . reverse $ bs