[英]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.