If I have a data type say:
data Color = Red | Yellow | Green
Is there a way I can turn this into a list of type [Color] getting all possibl
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.
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.
data Color = Red
| Yellow
| Green
deriving Enum
allColors = [Red ..]