Json in Racket

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

Our first program will demonstrate JSON encoding and decoding in Racket. Here’s the full source code:

#lang racket

(require json)

; We'll use these two structs to demonstrate encoding and
; decoding of custom types below.
(struct response1 (page fruits) #:transparent)
(struct response2 (page fruits) #:transparent)

(define (main)
  ; First we'll look at encoding basic data types to
  ; JSON strings. Here are some examples for atomic values.
  (displayln (jsexpr->string #t))
  (displayln (jsexpr->string 1))
  (displayln (jsexpr->string 2.34))
  (displayln (jsexpr->string "gopher"))

  ; And here are some for lists and hash tables, which encode
  ; to JSON arrays and objects as you'd expect.
  (displayln (jsexpr->string '("apple" "peach" "pear")))
  (displayln (jsexpr->string #hash(("apple" . 5) ("lettuce" . 7))))

  ; The JSON package can automatically encode your
  ; custom data types.
  (define res1 (response1 1 '("apple" "peach" "pear")))
  (displayln (jsexpr->string res1))

  ; We can also use custom keys for JSON output
  (define res2 (response2 1 '("apple" "peach" "pear")))
  (displayln (jsexpr->string 
              (hash 'page (response2-page res2)
                    'fruits (response2-fruits res2))))

  ; Now let's look at decoding JSON data into Racket
  ; values. Here's an example for a generic data structure.
  (define byt "{\"num\":6.13,\"strs\":[\"a\",\"b\"]}")

  ; Here's the actual decoding
  (define dat (string->jsexpr byt))
  (displayln dat)

  ; In order to use the values in the decoded hash table,
  ; we can access them directly.
  (define num (hash-ref dat 'num))
  (displayln num)

  ; Accessing nested data
  (define strs (hash-ref dat 'strs))
  (define str1 (first strs))
  (displayln str1)

  ; We can also decode JSON into custom data types.
  (define str "{\"page\": 1, \"fruits\": [\"apple\", \"peach\"]}")
  (define res (string->jsexpr str))
  (displayln res)
  (displayln (first (hash-ref res 'fruits)))

  ; In Racket, we can write JSON directly to output ports
  (define d #hash(("apple" . 5) ("lettuce" . 7)))
  (write-json d))

(main)

To run the program, save it as json-example.rkt and use racket:

$ racket json-example.rkt
true
1
2.34
"gopher"
["apple","peach","pear"]
{"apple":5,"lettuce":7}
{"page":1,"fruits":["apple","peach","pear"]}
{"page":1,"fruits":["apple","peach","pear"]}
#hash((num . 6.13) (strs . ("a" "b")))
6.13
a
#hash((page . 1) (fruits . ("apple" "peach")))
apple
{"apple":5,"lettuce":7}

We’ve covered the basics of JSON in Racket here. The json module in Racket provides functions for JSON encoding and decoding. Unlike Go, Racket uses hash tables (#hash) to represent JSON objects and lists to represent JSON arrays.

Racket’s dynamic typing means we don’t need to specify types for our JSON data structures explicitly. The jsexpr->string function is used for encoding Racket expressions to JSON strings, while string->jsexpr is used for decoding JSON strings to Racket expressions.

For custom data types, we use Racket’s struct system. The #:transparent option allows the struct’s fields to be easily accessed and displayed.

Racket’s pattern matching and functional programming features can make working with JSON data very convenient, especially when dealing with complex nested structures.