OrenIshShalom
OrenIshShalom

Reputation: 7142

Haskell-ish way to define values for enums

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.

Upvotes: 3

Views: 405

Answers (2)

Daniel Wagner
Daniel Wagner

Reputation: 152907

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.

Upvotes: 2

MMZK1526
MMZK1526

Reputation: 765

(+), (-) 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.

Upvotes: 0

Related Questions