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
.