[Haskell-cafe] Custom Enum instance with non-consecutive indices

Nicolas Trangez nicolas at incubaid.com
Sat Nov 17 15:44:57 CET 2012


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!

Thanks,

Nicolas




More information about the Haskell-Cafe mailing list