如何在Haskell中使记录类型位可寻址?

时间:2011-06-30 00:07:29

标签: haskell types functional-programming

我有一个4 Word32的记录类型。

data MyType = MyType {a :: Word32, b :: Word32, c :: Word32, d :: Word32 }

大多数情况下,我想将此类型视为4个单独的Word32。但是,有时我希望将其视为单个二进制数据流(128位长,4个Word32的串联)。我知道在Python中,我会为这个“结构”编写不同的访问器函数,这样我就可以通过两种方式读取/修改它。但这是Haskell。我想知道经验丰富的Haskeller会如何解决这个问题?

2 个答案:

答案 0 :(得分:9)

有一个课程: - )

import Data.Bits

newtype MyWord128 = MyWord128 MyType

instance Num MyWord128 where
   -- implement this one

instance Bits MyWord128 where
   -- and then this one, which is what you really want

查看documentation for Data.Bits。一个完整的最小定义是提供.&..|.complementshiftrotatebitSize和{{1}的实现(或其他一些可能的组合:有关详细信息,请参阅文档)。令人讨厌的是,你还必须实现isSigned,尽管我并不完全清楚为什么他们这样定义。

答案 1 :(得分:5)

如果你真的希望它像四个word32的结构,你可能想要使用strict / unpacked字段:

data MyType = MyType { a :: {-# UNPACK #-} !Word32
                     , b :: {-# UNPACK #-} !Word32
                     , c :: {-# UNPACK #-} !Word32
                     , d :: {-# UNPACK #-} !Word32 }
  deriving (Show)

然后,让我们定义一些比特小功能:

mask :: Bits a => Int -> a
mask count = (1 `shiftL` count) - 1

bitRange :: Bits a => Int -> Int -> a -> a
bitRange low count val = (val `shiftR` low) .&. mask count

现在您可以为此类型编写128位访问器:

from128 :: Integer -> MyType
from128 val = MyType (bitsFrom 0)
                     (bitsFrom 32)
                     (bitsFrom 64)
                     (bitsFrom 96)
  where
    bitsFrom i = fromIntegral (bitRange i 32 val)

to128 :: MyType -> Integer
to128 (MyType a b c d) =
  foldl' (.|.) 0 [
    bitsTo a 0,
    bitsTo b 32,
    bitsTo c 64,
    bitsTo d 96
  ]
  where
    bitsTo val i = fromIntegral val `shiftL` i

对于a b c d字段,您只需使用fclabels即可。你也可以制作一个fclabel双射Functor (:<->:)

myType128 :: MyType :<->: Integer
myType128 = to128 :<->: from128