How to decode tagged union types in Elm?

一笑奈何 提交于 2019-12-23 08:54:15

问题


If I have a certain tagged union type, like Shape here, how would I construct a JSON decoder for it in Elm?

type alias Rectangle = { width : Int, height : Int }

type alias Circle = { radius: Int }

type Shape 
    = ShapeRectangle Rectangle 
    | ShapeCircle Circle

回答1:


Given your JSON looks like

{ "radius" : 10 }

or

{ "width" : 20, "height" : 15}

Then this will do the trick

import Json.Decode as Json exposing ((:=))

decodeShape : Json.Decoder Shape
decodeShape =
  Json.oneOf
    [ decodeShapeRectangle
    , decodeShapeCircle
    ]

decodeShapeRectangle : Json.Decoder Shape
decodeShapeRectangle =
  Json.map ShapeRectangle <|
    Json.object2 Rectangle
       ("width" := Json.int)
       ("height" := Json.int)


decodeShapeCircle : Json.Decoder Shape
decodeShapeCircle =
    Json.object1 (ShapeCircle << Circle)
         ("radius" := Json.int)

A couple of additional things: I often add a 'type' and 'tag' field to help disambiguate when I have data types with common field names. The JSON then looks like

{ "type":"shape", "tag":"circle", "radius":10 }

Also, I think := will be replaced by field in the upcoming 0.18 release.

Regards,

Michael




回答2:


Michel Thoma's answer shone a great light here.

You can tag decoded values using Json.Decode.map or andThen like this:

`andThen` \x -> decode (MyTag x)

Using here is a solution using andThen and Json.Decode.Pipeline

import Json.Decode exposing ( Decoder, decodeString, int, andThen, oneOf )
import Json.Decode.Pipeline exposing ( decode, required )

import Html

main =
  let
    decoded = decodeString decodeShape "{ \"radius\": 2 }"
   in
     case decoded of
       Ok shape ->
         Html.text <| toString shape

       Err error ->
         Html.text error

type alias Rectangle = { width : Int, height : Int }

type alias Circle = { radius: Int }

type Shape
    = ShapeRectangle Rectangle
    | ShapeCircle Circle



decodeShape : Decoder Shape
decodeShape =
  oneOf
    [ decodeRectangle `andThen` \x -> decode (ShapeRectangle x)
    , decodeCircle `andThen` \x -> decode (ShapeCircle x)
    ]



decodeRectangle : Decoder Rectangle
decodeRectangle =
    decode Rectangle
        |> required "width" int
        |> required "height" int




decodeCircle : Decoder Circle
decodeCircle =
    decode Circle
         |> required "radius" int


来源:https://stackoverflow.com/questions/40193642/how-to-decode-tagged-union-types-in-elm

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!