
Hi Nicolas,
The simplest approach would be to use the standard (derived) Enum
instance that would be used for enumerations (like [Flag1..]), and
have your own functions to convert to/from magic constants.
Roman
* Nicolas Trangez
All,
I've been working on a server implementation of an existing networking protocol. The protocol uses "magic constants" in some places (e.g. to tag message types), as well as bitfields, or a combination of both packed in a single value.
I created data types for both the identifiers as well as the bitfield masks, e.g.
import Data.Bits
data MessageType = Message1 | Message2 | Message5
data MessageFlag = Flag1 | Flag2
Since I need to be able to get a numeric representation of them, I thought making a custom Enum instance would make sense:
instance Enum MessageType where fromEnum a = case a of Message1 -> 1 Message2 -> 2 Message5 -> 5 toEnum n | n == 1 = Message1 | n == 2 = Message2 | n == 5 = Message5
instance Enum MessageFlag where fromEnum a = case a of Flag1 -> 1 `shiftL` 0 Flag2 -> 1 `shiftL` 1 toEnum n | n == 1 `shiftL` 0 = Flag1 | n == 1 `shiftL` 1 = Flag2
This is not a complete definition (not to mention non-exhaustive pattern matches), so I was wondering what the best practices are to extend this so these instances are 'correct'?
I've been trying several approaches, but all of them failed on code like
getFlags :: Int -> [MessageFlag] getFlags i = filter (\v -> (i .&. fromEnum v) /= 0) [Flag1 ..]
Unless I hard-code all options in the last list, of course, but this is obviously not the intention.
Any help or pointers (including "This is not how Enum is intended to be used") would be appreciated!