There are a few different ways you can do it, depending on your taste. Using a library like Don mentioned is probably the best option, otherwise you can try something along the lines of these:
doubleToBytes :: Double -> [Int]
doubleToBytes d
= runST (do
arr <- newArray_ ((0::Int),7)
writeArray arr 0 d
arr <- castDoubleToWord8Array arr
i0 <- readArray arr 0
i1 <- readArray arr 1
i2 <- readArray arr 2
i3 <- readArray arr 3
i4 <- readArray arr 4
i5 <- readArray arr 5
i6 <- readArray arr 6
i7 <- readArray arr 7
return (map fromIntegral [i0,i1,i2,i3,i4,i5,i6,i7])
)
-- | Store to array and read out individual bytes of array
dToStr :: Double -> String
dToStr d
= let bs = doubleToBytes d
hex d' = case showHex d' "" of
[] -> error "dToStr: too few hex digits for float"
[x] -> ['0',x]
[x,y] -> [x,y]
_ -> error "dToStr: too many hex digits for float"
str = map toUpper $ concat . fixEndian . (map hex) $ bs
in "0x" ++ str
-- | Create pointer to Double and cast pointer to Word64, then read out
dToStr2 :: Double -> IO String
dToStr2 f = do
fptr <- newStablePtr f
let pptr = castStablePtrToPtr fptr
let wptr = (castPtrToStablePtr pptr)::(StablePtr Word64)
w <- deRefStablePtr wptr
let s = showHex w ""
return ("0x" ++ (map toUpper s))
-- | Use GHC specific primitive operations
dToStr3 :: Double -> String
dToStr3 (D# f) = "0x" ++ (map toUpper $ showHex w "")
where w = W64# (unsafeCoerce# f)
Three different ways. Last is GHC specific. Other two may work with other Haskell compilers but are relying a little on the underlying implementation so hard to guarantee.