Home > Software engineering >  Decode a JSON tuple to Elm tuple
Decode a JSON tuple to Elm tuple

Time:01-16

My JSON looks like the following

{ "resp":
    [ [1, "things"]
    , [2, "more things"]
    , [3, "even more things"]
    ]
}

the problem is that I can't parse the JSON tuples into Elm tuples:

decodeThings : Decoder (List (Int, String))
decodeThings = field "resp" <| list <| map2 (,) int string

It compiles, but when ran, it throws

BadPayload "Expecting an Int at _.resp[2] but instead got [3, \"even more things\"]

For some reason it reads [3, "even more things"] as only one thing and not as tuple in JSON format.
How can I parse my JSON into a List (Int, String)?

CodePudding user response:

The accepted answer is more complicated than it needs to be. Try:

import Json.Decode as Decode

decodeTuple : Decode.Decoder (Int, String)
decodeTuple = 
    Decode.map2 Tuple.pair 
        (Decode.index 0 Decode.int) 
        (Decode.index 1 Decode.string)

and then, as you note, for the list

Decode.list decodeTuple

CodePudding user response:

You need a decoder which turns a javascript array of size two into an Elm tuple of size two. Here is an example decoder:

arrayAsTuple2 : Decoder a -> Decoder b -> Decoder (a, b)
arrayAsTuple2 a b =
    index 0 a
        |> andThen (\aVal -> index 1 b
        |> andThen (\bVal -> Json.Decode.succeed (aVal, bVal)))

You can then amend your original example as follows:

decodeThings : Decoder (List (Int, String))
decodeThings = field "resp" <| list <| arrayAsTuple2 int string

(Note that my example decoder does not fail if there are more than two elements, but it should get you pointed in the right direction)

CodePudding user response:

I could not get either Chad Gilbert's or Simon H's solution to work with Elm 0.19. I am quite new to Elm, but this is what I could get to work:

import Json.Decode as Decode
import Json.Decode.Extra as Decode

{-| Decodes two fields into a tuple.
-}
decodeAsTuple2 : String -> Decode.Decoder a -> String -> Decode.Decoder b -> Decode.Decoder (a, b)
decodeAsTuple2 fieldA decoderA fieldB decoderB =
    let
        result : a -> b -> (a, b)
        result valueA valueB =
            (valueA, valueB)
    in
        Decode.succeed result
            |> Decode.andMap (Decode.field fieldA decoderA)
            |> Decode.andMap (Decode.field fieldB decoderB)
  • Related