Подтвердить что ты не робот

Получение списка всех возможных значений типа данных в Haskell

Если у меня есть тип данных, скажите:

data Color = Red | Yellow | Green

Есть ли способ превратить это в список типа [Цвет], получая все возможные значения? [Красный, Желтый, Зеленый]

Возможно, это полный анти-шаблон?

4b9b3361

Ответ 1

data Color = Red
           | Yellow
           | Green
           deriving Enum

allColors = [Red ..]

Ответ 2

Не уверен, что это анти-шаблон (и я не думаю о хорошем использовании прямо сейчас), но это возможно. Используйте Enum (позволяет создавать классы типа [someCtor .. someOtherCtor]) и Bounded (для minBound и maxBound). К счастью, вы можете получить оба:

data Color = Red
           | Yellow
           | Green
           deriving (Enum, Bounded)

allColors = [(minBound :: Color) ..]

Если вы когда-либо добавляли другой цвет, allColors обновляются автоматически. Одно ограничение: Enum требует, чтобы все контрмеры были нулевыми, т.е. Добавление Foo Int нарушает все. К счастью, потому что список всех возможных значений для этого был бы слишком большим.

Изменить: другой ответ также работает, может быть, лучше, поскольку для него не требуется вывод Bounded и, следовательно, немного короче. Я все равно оставлю свой, потому что мне нравится сверхналоженный, но чрезвычайно общий код;)

Ответ 3

Разумеется, delnan ответ лучше. Поскольку я не знаю, как включить кусок кода в комментарий, я дам обобщение в качестве отдельного ответа здесь.

allValues :: (Bounded a, Enum a) => [a]
allValues = [minBound..]

Теперь это работает для любого типа с экземпляром Bounded и Enum! И allColors - это просто частный случай:

allColors :: [Color]
allColors = allValues

Во многих случаях вам даже не нужно определять allColors отдельно.

Ответ 4

Вот пример использования этого метода для синтаксического анализа перечислений с помощью Parsec

data FavoriteColor = Maroon | Black | Green  | Red | 
                     Blue   | Pink  | Yellow | Orange
                             deriving (Show, Read, Enum, Bounded)

И парсер парсера

parseColor :: Parser FavoriteColor           
parseColor = fmap read . foldr1 (<|>) $ map (try . string . show) 
  [ minBound :: FavoriteColor ..] 

конечно, попытка может быть применена лучше с помощью сопоставления с образцом, а некоторые другие могут сделать ее более приятной, но это всего лишь пример использования этой техники.