On Monday, March 13, 2017 at 11:24:05 PM UTC, vis...@stanford.edu wrote: > > Decode.lazy was what I was looking for, thank you! > > However, now I have a new problem. Here is the new definitions of the > decoders: > > > type alias Elem = > { tag : String, attrs : List ( String, String ), body : List Template } > > > type Template > = Body String > | Tag Elem > > > > decodeTemplate : Json.Decoder Template > decodeTemplate = > Json.oneOf [ Json.map Tag decodeElem, Json.map Body Json.string ] > > > decodeElem : Json.Decoder Elem > decodeElem = > Json.map3 Elem > (Json.field "tag" Json.string) > (Json.field "attrs" (Json.keyValuePairs Json.string)) > (Json.field "body" (Json.list (Json.lazy (\_ -> decodeTemplate)))) > > I got the decoder to compile, but only by using oneOf. Is there a better > way to decode ADT's with multiple branches? Am I guaranteed to have the > decoders be tried in the order that they are put in the list? >
I am actually going to change this and use a Dict instead. The reason being that I want to be able to dynamically handle any kind of 'ContentModel', not just the ones I may currently have defined. But here is another snippet from my code that may help you. In my Java code, I have a class hierarchy. ContentModel can be one of three things. So I represented this as a tagged union type in Elm. I also added a field to the json to say which sub-class something is, and I put this in the '@type' field on the json object. Encoders/decoders are: type ContentModel = TitledAsContentModel Titled | MdContentAsContentModel MdContent | PanelAsContentModel Panel contentModelEncoder : ContentModel -> Encode.Value contentModelEncoder model = case model of TitledAsContentModel titled -> titledEncoder titled MdContentAsContentModel mdContent -> mdContentEncoder mdContent PanelAsContentModel panel -> panelEncoder panel contentModelDecoder : Decoder ContentModel contentModelDecoder = let toContentModel typeName = case typeName of "Titled" -> map TitledAsContentModel titledDecoder "MdContent" -> map MdContentAsContentModel mdContentDecoder "Panel" -> map PanelAsContentModel panelDecoder _ -> Decode.fail ("unknown type: " ++ typeName) in field "@type" Decode.string |> andThen toContentModel So I decode the @type field 'andThen' apply the appropriate decoder for the tagged union constructor that is the correct one to use. You can use 'oneOf' and I think it does try things in the order you ask, but it is also inefficient in that you will end up trying decoders that you know will fail. It also may not work if you have optional fields in your json, and they can be missing in such a way that different sub-classes cannot really be distinguished from one another, if you see what I mean. -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.