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.
