Probably useful to include a "mkFixed" function example as well, to show how a Fixed can be constructed using the "optimal" data representation:
-- | Make a fixed field.
--
-- Note that this type constructor function chooses the minimal type
-- representation for the fixed value stored. Unsigned representations
-- are preferred over signed.
mkFixed :: String -> Int -> Integer -> Member
mkFixed name len val
| len <= 0 = error $ "mkFixed " ++ name ++ ": length < 0"
| len < 8 && validUnsigned len val = Fixed name len False (fromIntegral val :: Word8)
| len < 8 && validSigned len val = Fixed name len True (fromIntegral val :: Int8)
| len < 16 && validUnsigned len val = Fixed name len False (fromIntegral val :: Word16)
| len < 16 && validSigned len val = Fixed name len True (fromIntegral val :: Int16)
| len < 32 && validUnsigned len val = Fixed name len False (fromIntegral val :: Word32)
| len < 32 && validSigned len val = Fixed name len True (fromIntegral val :: Int32)
| len < 64 && validUnsigned len val = Fixed name len False (fromIntegral val :: Word64)
| len < 64 && validSigned len val = Fixed name len True (fromIntegral val :: Int64)
| otherwise = error $ "mkFixed " ++ name ++ ": cannot represent this bit field"
Here's an example (not a complete module) I was using to represent bit-oriented structures as they occur in certain space applications, notably GPS frames. "Fixed" allows for fixed-sized fields and lets the end user choose the integral type that's best for the structure.
At least it's not a parser or language example. :-)
-scooter
-- | Member fields, etc., that comprise a 'BitStruct'
data Member where
Field :: String -- Field name
-> Int -- Field length
-> Bool -- Signed (True) or unsigned (False)
-> Member
ZeroPad :: String -- Field name
-> Int -- Field length
-> Member
OnesPad :: String -- Field name
-> Int -- Field length
-> Member
ArbPad :: String -- Field name
-> Int -- Field length
-> Member
Reserved :: String -- Field name
-> Int -- Field length
-> Member
Fixed :: (Integral x, Show x) =>
String -- Field name
-> Int -- Field length
-> Bool -- Signed (True) or unsigned (False)
-> x -- Type of the fixed field's value
-> Member
Variant :: (Integral x, Show x) =>
String -- Variant prefix name
-> Maybe BitStruct -- Header before the tag
-> TagElement -- The tag element itself
-> Maybe BitStruct -- Common elements after the tag
-> Seq (x, BitStruct) -- Variant element tuples (value, structure)
-> Member
-- Mult-value variant: Use this when multiple variant tag values have the
-- same structure:
MultiValueVariant :: (Integral x, Show x) =>
String -- Variant prefix name
-> Maybe BitStruct -- Header before the tag
-> TagElement -- The tag element itself
-> Maybe BitStruct -- Common elements after the tag
-> Seq ([x], BitStruct) -- Variant element tuples ([values], structure)
-> Member