Прежде всего, кажется, что вы хотите ограничить параметр doc
для DocChange
значением Doc
, поэтому вам, вероятно, следует определить его следующим образом:
type DocChange data
= Added (Doc data)
| Modified (Doc data)
| Removed (Doc data)
В противном случае вам придется многократно указывать DocChange (Doc data)
в аннотациях типов функций, что быстро становится раздражающим, и чем хуже, тем больше вы его вкладываете. В любом случае, я продолжил использовать типы, как вы их определили:
decodeDocData : Decoder DocData
decodeDocData =
map2 DocData
(field "title" string)
(field "subtitle" string)
decodeDoc : Decoder data -> Decoder (Doc data)
decodeDoc dataDecoder =
map2 Tuple.pair
(field "id" string)
(field "data" dataDecoder)
decodeDocChange : Decoder data -> Decoder (DocChange (Doc data))
decodeDocChange dataDecoder =
field "type" string
|> andThen
(\typ ->
case typ of
"added" ->
map Added
(field "doc" (decodeDoc dataDecoder))
"modified" ->
map Modified
(field "doc" (decodeDoc dataDecoder))
"removed" ->
map Removed
(field "doc" (decodeDoc dataDecoder))
_ ->
fail ("Unknown DocChange type: " ++ typ)
)
Хитрость заключается в том, чтобы сначала декодировать "type"
, а затем использовать andThen
, чтобы включить его и выбрать подходящий декодер. В этом случае форма одинакова для всех «типов», но это может быть не так, и этот шаблон также дает возможность обрабатывать расходящиеся формы. Это можно упростить, просто выбрав конструктор и сохранив остальную часть общего декодирования, если вы абсолютно уверены, что они не расходятся.