Question

I have a sum type of records to represent all in-memory tables and as I will send them across the network. I have a binary protocol and need to initially pass the ordinal value (fromEnum) in the header to determine which table the data is associated with. The problem is that the sum type needs to derive from Enum but it doesn't want to.

data Table = MarketData {bid::[Float], ask::[Float]}
     | Trade {price::[Float], qty::[Float]} 
        deriving Enum

main :: IO ()
main = do
    print $ fromEnum Trade

This is the compilation error

Can't make a derived instance of `Enum Table':
  `Table' must be an enumeration type
  (an enumeration consists of one or more nullary, non-GADT constructors)
In the data declaration for `Table'

Any ideas of how I can do this without having to write boilerplate like this:

ordinalVal :: Table -> Int
ordinalVal tbl = case tbl of
      MarketData{bid=_, ask=_} -> 0
    | Trade{price=_, qty=_} -> 1
Was it helpful?

Solution

If you only want to enumerate the constructors, you can you the Data.Data module, like so:

{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data

data T a b = C1 a b | C2 deriving (Typeable, Data)

main = print $ constrIndex $ toConstr x
  where
    x :: T Int Int
    x = C1 1 1  -- will print 1
    -- x = C2  -- will print 2

If you don't want to go down the road of using the Typebale and Data type classes, you could also simply write a function Table -> Int, like you proposed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top