Можно ли перебирать тип соединения в Elm?

У меня есть тип объединения цветов, которые я хочу отобразить пользователю. Можно ли перебирать все значения объединения типов?

type Color = Red | Blue | Green | Black

colorToStirng color = 
    case color of
        Red -> "red"
        Blue -> "blue"
        Green -> "green"
        Black -> "black"

colorList = 
    ul
        []
        List.map colorListItem Color  -- <- this is the missing puzzle

colorListItem color = 
    li [class "color-" ++ (colorToString color) ] [ text (colorToString color) ]

Ответ 1

К сожалению, нет. Это невозможно.

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

type Thing = Thing String

Для повторения всех значений типа Thing потребуется выполнить итерацию по всем значениям типа String.

Ответ 2

Проблема с объявлением функции вроде:

type Foo 
  = Bar 
  | Baz

enumFoo = 
  [ Bar 
  , Baz ]

является то, что вы, вероятно, забудете добавить новые перечисления к нему. Чтобы решить эту проблему, я играл с этой (хакерской, но менее хакерской, чем идея выше) идеей:

enumFoo : List Foo
enumFoo =
  let
    ignored thing =
      case thing of
          Bar ->  ()
          Baz -> ()
          -- add new instances to the list below!
  in [ Bar, Baz ]

Таким образом, вы по крайней мере получите ошибку для функции и, надеюсь, не забудьте добавить ее в список.

Ответ 3

Конечно, вы можете это сделать. Просто не автоматически через компилятор.

type Foo 
   = Bar 
   | Baz
   | Wiz

-- just write this for types 
-- you wish to use as enumerations 
enumFoo = 
   [ Bar 
   , Baz
   , Wiz ]

Это работает отлично, но, очевидно, было бы лучше и исчерпывающе проверено, если перечисление всегда поддерживается компилятором.

colorList = 
ul
    []
    List.map colorListItem enumFoo