Not sure if it is an anti-pattern (nor can I think of a good use right now), but it's possible. Use the Enum
(allows to generate a list like [someCtor .. someOtherCtor]
) and Bounded
(for minBound
and maxBound
) type classes. Luckily, you can derive both:
data Color = Red
| Yellow
| Green
deriving (Enum, Bounded)
allColors = [(minBound :: Color) ..]
If you ever add another color, allColors get updated automatically. One restriction though: Enum
requires all contructors to be nullary, i.e. adding Foo Int
breaks the whole thing. Luckily, because a list of all possible values for this would be way too large.
Edit: The other answer works as well, maybe better since it doesn't require deriving Bounded
and is therefore a bit shorter. I'll still leave mine because I love over-engineered but extremely generic code ;)
Surely delnan's answer is better. Since I do not know how to include a piece of code in a comment, I'll give a generalisation as a separate answer here.
allValues :: (Bounded a, Enum a) => [a]
allValues = [minBound..]
Now, this works for any type with a Bounded
and Enum
instance! And allColors
is just a special case:
allColors :: [Color]
allColors = allValues
In many cases, you won't even need to define allColors
separately.
data Color = Red
| Yellow
| Green
deriving Enum
allColors = [Red ..]
Here is an example of using this technique to parse enums with Parsec
data FavoriteColor = Maroon | Black | Green | Red |
Blue | Pink | Yellow | Orange
deriving (Show, Read, Enum, Bounded)
And the parsec parser
parseColor :: Parser FavoriteColor
parseColor = fmap read . foldr1 (<|>) $ map (try . string . show)
[ minBound :: FavoriteColor ..]
of course the try could could be applied by better by pattern matching and a few other things could make it nicer but this is just an example of some usage of the technique.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With