Как мне сделать бит типа записи адресуемым в Haskell? - PullRequest
2 голосов
/ 30 июня 2011

У меня есть тип записи 4 Word32.

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

В большинстве случаев я хочу рассматривать этот тип как 4 отдельных Word32.Однако иногда я хочу рассматривать его как единый поток двоичных данных (длиной 128 бит, конкатенация из 4 Word32).Я знаю, что в Python я бы написал разные функции доступа для этой «структуры», чтобы я мог читать / изменять ее обоими способами.Но это Хаскелл.Мне интересно, как опытный Хаскеллер поступил бы по этому поводу?

Ответы [ 2 ]

9 голосов
/ 30 июня 2011

Для этого есть класс: -)

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

Ознакомьтесь с документацией для Data.Bits .Полное минимальное определение - обеспечить реализацию .&., .|., complement, shift, rotate, bitSize и isSigned (или нескольких других возможных комбинаций: подробности см. В документе).Досадно, что вам также нужно реализовать Num, хотя мне не совсем понятно, почему они так его определили.

5 голосов
/ 01 июля 2011

Если вы действительно хотите, чтобы это было похоже на структуру из четырех слов32, вы можете использовать строгие / распакованные поля:

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 (:<->:):

myType128 :: MyType :<->: Integer
myType128 = to128 :<->: from128
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...