Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decode a JSON tuple to Elm tuple

Tags:

json

elm

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)?

like image 774
ptkato Avatar asked Mar 09 '17 19:03

ptkato


Video Answer


3 Answers

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
like image 87
Simon H Avatar answered Oct 03 '22 12:10

Simon H


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)

like image 32
Chad Gilbert Avatar answered Oct 03 '22 11:10

Chad Gilbert


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)
like image 20
René Paw Christensen Avatar answered Oct 03 '22 12:10

René Paw Christensen