Home > Software design >  Haskell-ish way to define values for enums
Haskell-ish way to define values for enums

Time:08-10

I'm looking for a Haskell-ish way to define values for enums. Here is what I currently have:

data Binop
   = Plus
   | Minus
   | Times
   | Divide
   -- deriving ( Show ) <--- removed this

instance Show Binop where
    show Plus   = " "
    show Minus  = "-"
    show Times  = "*"
    show Divide = "/"

It would be nice to have the constant values (" ", "-" etc.) in the Binop data type.

CodePudding user response:

( ), (-) etc are not "values" that you want since they are functions, and you can't compare equality between functions like you would do with "normal values". Of course, you can create a function that translates the Binop to the corresponding binary operator function, and this could come handy when you implement evaluation-related functions.

However, Haskell Enums do come with intrinsic indices:

fromEnum :: Enum a => a -> Int

In this way, you can have fromEnum Plus = 0, fromEnum Minus = 1, and so on. All you need to do is deriving Enum immediately after defining the data Binop.

CodePudding user response:

What you wrote seems fine, modulo the usual complaint about a strong convention: the Show instance should produce valid Haskell code that reproduces the value. I might consider returning a Char instead of a String unless you're sure that String is better, so something like:

name :: Binop -> Char
name = \case
    Plus -> ' '
    Minus -> '-'
    Times -> '*'
    Divide -> '/'

If there's a lot of them, you could consider making a lookup table for compactness, though I'm not at all confident that this will be more efficient.

name :: Binop -> Char
name = (listArray (minBound, maxBound) " -*/" !)

I guess you'd need to define an Ix instance as well, but you can reuse the Ix Int and Enum Binop instances to make that pretty short; or use the same basic idea but backed by a Map instead of an Array.

  • Related