Json in Elm

Here’s the translation of the JSON handling example from Go to Elm:

module Main exposing (main)

import Html exposing (Html, div, text)
import Json.Decode as Decode
import Json.Encode as Encode

-- We'll use these two types to demonstrate encoding and
-- decoding of custom types below.
type alias Response1 =
    { page : Int
    , fruits : List String
    }

type alias Response2 =
    { page : Int
    , fruits : List String
    }

main : Html msg
main =
    div []
        [ encodeExamples
        , decodeExamples
        ]

encodeExamples : Html msg
encodeExamples =
    div []
        [ text "Encoding examples:"
        , text <| "Bool: " ++ Encode.encode 0 (Encode.bool True)
        , text <| "Int: " ++ Encode.encode 0 (Encode.int 1)
        , text <| "Float: " ++ Encode.encode 0 (Encode.float 2.34)
        , text <| "String: " ++ Encode.encode 0 (Encode.string "gopher")
        , text <| "List: " ++ Encode.encode 0 (Encode.list Encode.string ["apple", "peach", "pear"])
        , text <| "Object: " ++ Encode.encode 0 (Encode.object [ ("apple", Encode.int 5), ("lettuce", Encode.int 7) ])
        , text <| "Custom type 1: " ++ Encode.encode 0 (encodeResponse1 { page = 1, fruits = ["apple", "peach", "pear"] })
        , text <| "Custom type 2: " ++ Encode.encode 0 (encodeResponse2 { page = 1, fruits = ["apple", "peach", "pear"] })
        ]

encodeResponse1 : Response1 -> Encode.Value
encodeResponse1 response =
    Encode.object
        [ ("Page", Encode.int response.page)
        , ("Fruits", Encode.list Encode.string response.fruits)
        ]

encodeResponse2 : Response2 -> Encode.Value
encodeResponse2 response =
    Encode.object
        [ ("page", Encode.int response.page)
        , ("fruits", Encode.list Encode.string response.fruits)
        ]

decodeExamples : Html msg
decodeExamples =
    let
        jsonString = """{"num":6.13,"strs":["a","b"]}"""
        decodedValue = Decode.decodeString decodeData jsonString
    in
    div []
        [ text "Decoding examples:"
        , text <| "Generic decode: " ++ Debug.toString decodedValue
        , text <| "Custom type decode: " ++ Debug.toString (Decode.decodeString decodeResponse2 """{"page": 1, "fruits": ["apple", "peach"]}""")
        ]

decodeData : Decode.Decoder (Float, List String)
decodeData =
    Decode.map2 Tuple.pair
        (Decode.field "num" Decode.float)
        (Decode.field "strs" (Decode.list Decode.string))

decodeResponse2 : Decode.Decoder Response2
decodeResponse2 =
    Decode.map2 Response2
        (Decode.field "page" Decode.int)
        (Decode.field "fruits" (Decode.list Decode.string))

This Elm code demonstrates JSON encoding and decoding, which is analogous to the Go example. Here are some key points:

  1. Elm uses the Json.Encode and Json.Decode modules for handling JSON.

  2. We define custom types Response1 and Response2 similar to the structs in the Go example.

  3. The encodeExamples function shows how to encode various data types to JSON strings.

  4. Custom encoding functions encodeResponse1 and encodeResponse2 are defined to handle our custom types.

  5. The decodeExamples function demonstrates decoding JSON strings into Elm values.

  6. We define custom decoders decodeData and decodeResponse2 to handle specific JSON structures.

  7. Elm’s type system ensures type safety when working with JSON data.

  8. Unlike Go, Elm doesn’t have concepts like pointers or panic. Error handling is done through the Result type.

  9. Elm doesn’t have a direct equivalent to Go’s streaming JSON to os.Writer. Instead, you would typically use the encoded JSON string in HTTP requests or for other purposes.

This example showcases Elm’s strong typing and functional approach to handling JSON data, which differs from Go’s more imperative style but achieves similar results.