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

Ste*_*gle 2 haskell types functional-programming

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

data MyType = MyType {a :: Word32, b :: Word32, c :: Word32, d :: Word32 }
Run Code Online (Sandbox Code Playgroud)

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

Lam*_*eek 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
Run Code Online (Sandbox Code Playgroud)

查看Data.Bits文档.一个完整的最小定义是提供一个实现.&.,.|.,complement,shift,rotate,bitSizeisSigned(或其他一些可能的组合:详见DOC).令人讨厌的是你也必须实现Num,尽管我并不完全清楚为什么他们这样定义它.


Pea*_*ker 5

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

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

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

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
Run Code Online (Sandbox Code Playgroud)

现在您可以为此类型编写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
Run Code Online (Sandbox Code Playgroud)

对于a b c d字段,您可以使用fclabels.你也可以制作一个fclabel bijective Functor (:<->:):

myType128 :: MyType :<->: Integer
myType128 = to128 :<->: from128
Run Code Online (Sandbox Code Playgroud)