如何解码Elm中标记的联合类型?

时间:2016-10-22 15:08:09

标签: json elm decoder

如果我有一个标记的联合类型,比如Shape,我将如何在Elm中为它构建一个JSON解码器?

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

type alias Circle = { radius: Int }

type Shape 
    = ShapeRectangle Rectangle 
    | ShapeCircle Circle

2 个答案:

答案 0 :(得分:10)

鉴于您的JSON看起来像

gcloud beta container node-pools create --preemptible NAME

{ "radius" : 10 }

然后这将解决问题

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

还有一些额外的东西:我经常添加一个'类型'和'标记'当我有具有公共字段名称的数据类型时,有助于消除歧义的字段。然后JSON看起来像

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)

此外,我认为{ "type":"shape", "tag":"circle", "radius":10 }将在即将发布的0.18版本中被:=取代。

此致

迈克尔

答案 1 :(得分:2)

Michel Thoma的回答在这里引起了广泛关注。

您可以使用Json.Decode.mapandThen标记已解码的值,如下所示:

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

使用此处是使用andThen和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