Reputation: 4006
What would be an idiomatic way of generating an unique number (say, a 64bit unsigned int) from two values, in such a way that the input values (also numbers of the same type) could be regenerated from the number, as a Haskell function?
On C/C++ I would probably use something like
result = (((value1) << BITS) + ((value2) & ((1 << BITS) - 1)))
and, accordingly,
value1 = (result >> BITS)
and
value2 = (result & ((1 << BITS) - 1))
for regenerating the values, but I don't think I should be trying to use bitwise operations in Haskell.
After consideration, I simply abandoned the idea of using bitwise operations and resorted to Cantor's pairing function:
pair :: (Fractional a) => a -> a -> a
pair x y = (1 / 2) * (x + y) * (x + y + 1) + y
unpair :: (RealFrac a, Floating a) => a -> (a, a)
unpair z = (x, y) where
q = (-1 / 2) + sqrt (1 / 4 + 2 * z)
j = fromInteger (truncate q)
y = z - ((1 / 2) * j * (j + 1))
x = j - y
This is probably the way I should have thought from the beginning. Thank you all very much for helping me to better understand bit operations on Haskell, though.
Upvotes: 2
Views: 314
Reputation: 24822
You can use the exact same way in Haskell. Bitwise operations can be found in Data.Bits
and unsigned, fixed-sized integer types in Data.Word
. For example:
import Data.Bits
import Data.Word
combine :: Word32 -> Word32 -> Word64
combine a b = (fromIntegral a `shiftL` 32) + fromIntegral b
separate :: Word64 -> (Word32, Word32)
separate w = (fromIntegral $ w `shiftR` 32, fromIntegral $ w .&. 0xffff)
The thing that might trip you up compared to C is that Haskell never converts between different numeric types implicitly, so you need to use fromIntegral
to convert between e.g. 32bit and 64bit unsigned integers.
Upvotes: 4