2014-05-01 37 views
3

我想在Haskell中進行小端轉換,以便我可以將Word16轉換爲兩個Word8(例如258 = 1 * 256 + 2,因此結果應該是[2,1 ])。然後我將結果打包成一個ByteString。Haskell中的Word8和Word16之間的轉換

我創建了下面的代碼用於此目的:

import Data.Word 
import Data.Bits 

getByte b num = shift (relevantBits b num) (shiftNum b) 
    where bitMask b = sum $ map (2^) [8*b-8 .. 8*b-1] 
      relevantBits b num = num .&. bitMask b 
      shiftNum b = 8-8*b 

encodeWord16 x = [getByte 1 x, getByte 2 x] 

input :: Word16 
input = 355 

output :: [Word8] 
output = encodeWord16 input 

功能getByte從一些num得到字節數b。函數encodeWord16使用此輔助函數進行小端轉換。

然而,這並不編譯,我得到的錯誤:

Couldn't match expected type `Word8' with actual type `Word16' 
In the first argument of `encodeWord16', namely `input' 
In the expression: encodeWord16 input 
In an equation for `output': output = encodeWord16 input 

我(非常不繫統)試圖通過隨機分佈fromIntegral表達式來達到預期的效果,但顯然我的Haskell的類型系統的理解是不足以解決這個問題。有沒有系統的方法來解決這個問題? 基本上我想要功能encodeWord16有類型簽名Word16 -> [Word8]

回答

2

如何提取那些直接字節?就像這樣:

encodeWord16 x = [ x .&. 0xFF, (x .&. 0xFF00) `shiftR` 8 ] 

如果你想的encodeWord16簽名是Word16 -> [Word8],然後纔將其添加map fromIntegral,就像這樣:

encodeWord16 :: Word16 -> [Word8] 
encodeWord16 x = map fromIntegral [ x .&. 0xFF, (x .&. 0xFF00) `shiftR` 8 ] 
+0

是的,這看起來像一個更有效的方式來做到這一點。我仍然需要應用'來自整體的地圖'(參見AndrásKovács的回答)。 – Julian

+0

@Julian是的,因爲如果'x'的類型是'Word16',那麼'x。&的類型。 0xFF'也將是'Word16'。 –

+0

有沒有辦法做Word8 - > [Word8]?也叫他們把位列表 – astiefel

6

fromIntegral可用於各種整數類型之間的轉換。

fromIntegral :: (Num b, Integral a) => a -> b 

encodeWord16 :: Word16 -> [Word8] 
encodeWord16 x = map fromIntegral [getByte 1 x, getByte 2 x] 

這將會是更好的,雖然有getByte回報Word8 -s:

getByte :: Int -> Word16 -> Word8 
getByte b num = fromIntegral $ shift (relevantBits b num) (shiftNum b) 
    -- where ... 
1

binary包含以下代碼:

-- Words16s are written as 2 bytes in big-endian (network) order 
instance Binary Word16 where 
    put  = putWord16be 

http://hackage.haskell.org/package/binary-0.7.1.0/docs/Data-Binary.html#g:1

-- | Write a Word16 in big endian format 
putWord16be :: Word16 -> Builder 
putWord16be w = writeN 2 $ \p -> do 
    poke p    (fromIntegral (shiftr_w16 w 8) :: Word8) 
    poke (p `plusPtr` 1) (fromIntegral (w)    :: Word8) 

http://hackage.haskell.org/package/binary-0.7.1.0/docs/Data-Binary-Builder.html#g:5

所以你可以使用它像這樣:

> encode (355 :: Word16) 
"\SOHc" 
> toLazyByteString $ putWord16be 355 
"\SOHc" 
> index (encode (355 :: Word16)) 0 
1 
> index (toLazyByteString $ putWord16be 355) 0 
1 
> index (encode (355 :: Word16)) 1 
99 
> index (toLazyByteString $ putWord16be 355) 1 
99 
2

相反編碼手工的轉換,您可能需要使用預定義的功能,這樣做。

import Data.Word 
import Data.ByteString.Builder 
import Data.ByteString.Lazy (unpack) 

encodeWord16 :: Word16 -> [Word8] 
encodeWord16 = unpack . toLazyByteString . word16LE