我如何Json.decode联合类型?

时间:2017-01-31 23:29:39

标签: json elm

我在module Foo exposing (..)内有类似的定义:

type Foo
    = Bar
        { a : String
        , b : String
        }
    | Baz
        ...

然后我尝试在单独的模块中创建一个Json Decoder来解码这样的类型:

barDecoder : Decoder Bar
barDecoder =
    map2 Bar
        (field "a" string)
        (field "b" string)

Elm编译器在map2 Bar行上给出了一个错误,指出找不到类型Bar。包含解码器的模块具有import Foo exposing (..)。我也尝试将此函数移动到包含类型定义的同一模块中并获得相同的错误,因此它与在单独的模块中没有任何关系。

我已尝试将其更改为map2 Foo.Bar,但这也无效。

解码这样的联合类型的正确方法是什么?

2 个答案:

答案 0 :(得分:9)

如果你有多种解码方式,你应该使用Json.Decode.oneOf

以下是如何使用它的示例。 (我编造了Baz因为你没有指定它。)

import Json.Decode as Json

type Foo
    = Bar
        { a : String
        , b : String
        }
    | Baz Int


barDecoder : Json.Decoder Foo
barDecoder =
    Json.map2 (\x y -> Bar { a = x, b = y })
        (Json.field "a" Json.string)
        (Json.field "b" Json.string)


bazDecoder : Json.Decoder Foo
bazDecoder =
    Json.map Baz Json.int


fooDecoder : Json.Decoder Foo
fooDecoder =
    Json.oneOf [ barDecoder, bazDecoder ]

答案 1 :(得分:3)

Foo是类型。 Bar是构造函数。签名应该是:

barDecoder : Decoder Foo

此外,您将在当前解码器上收到编译错误。让我们为Bar中的记录内容添加别名:

type alias BarContents =
    { a : String
    , b : String
    }

type Foo
    = Bar BarContents
    | Baz

您的解码器可能如下所示:

barDecoder : Decoder Foo
barDecoder =
    Json.Decode.map Bar <|
         map2 BarContents
            (field "a" string)
            (field "b" string)