简体   繁体   English

在Haskell中在Word8和Word16之间进行转换

[英]Converting between Word8 and Word16 in Haskell

I am trying to to little endian conversion in haskell, so that I can turn a Word16 into two Word8 (for example 258 = 1*256 + 2, so result should be [2, 1]). 我试图在haskell中进行小端转换,以便我可以将Word16转换为两个Word8(例如258 = 1 * 256 + 2,因此结果应为[2,1])。 I then pack the result into a ByteString. 然后我将结果打包成ByteString。

I created the following code for this purpose: 我为此创建了以下代码:

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

The function getByte gets Byte number b from a number num . 函数getByte从数字num获取字节数b The function encodeWord16 uses this helper function to do the little endian conversion. 函数encodeWord16使用这个辅助函数来进行小端转换。

This however does not compile, I get the error: 但是这不能编译,我得到错误:

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

I (very unsystematically) tried to achieve the desired result by randomly distributing fromIntegral expressions, but obviously my understanding of the haskell type system is not good enough to solve this problem. 我(非常不系统地)尝试通过随机分布来自fromIntegral表达式来实现期望的结果,但显然我对haskell类型系统的理解不足以解决这个问题。 Is there a systematic way to approach this problem? 有没有系统的方法来解决这个问题? Basically I want the function encodeWord16 to have the type signature Word16 -> [Word8] . 基本上我希望函数encodeWord16具有类型签名Word16 -> [Word8]

fromIntegral can be used for conversion between various integral types. fromIntegral可用于各种整数类型之间的转换。

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

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

It'd be nicer though to have getByte return Word8 -s: getByte返回Word8 -s会更好:

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

Instead of coding the conversion by hand, you might want to use the predefined functions to do so. 您可能希望使用预定义的函数来执行此操作,而不是手动编码转换。

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

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

How about extract those bytes directly? 如何直接提取这些字节? Like this: 像这样:

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

If you want the signature of encodeWord16 be Word16 -> [Word8] , then add map fromIntegral before it, like this: 如果你想要encodeWord16的签名是Word16 -> [Word8] ,那么在它之前添加map fromIntegral ,就像这样:

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

binary contains the following code: 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 ) 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 ) http://hackage.haskell.org/package/binary-0.7.1.0/docs/Data-Binary-Builder.html#g:5

So you can just use it like this: 所以你可以像这样使用它:

> 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM