The JSONDecode structure

The JSONDecode structure implements combinators for decoding JSON values. The design is based on Elm's JSON.Decode module.

Synopsis

signature JSON_DECODE
structure JSONDecode : JSON_DECODE

Interface

exception JSONError of exn * JSON.value

exception NotBool
exception NotInt
exception NotNumber
exception NotString

exception NotObject
exception FieldNotFound of string

exception NotArray
exception ArrayBounds of int

val exnMessage : exn -> string

type 'a decoder

val decode : 'a decoder -> JSON.value -> 'a
val decodeString : 'a decoder -> string -> 'a
val decodeFile : 'a decoder -> string -> 'a

val bool : bool decoder
val int : int decoder
val intInf : IntInf.int decoder
val number : Real64.real decoder
val string : string decoder
val null : 'a -> 'a decoder

val raw : JSON.value decoder

val nullable : 'a decoder -> 'a option decoder

val try : 'a decoder -> 'a option decoder

val seq : 'a decoder -> ('a -> 'b) decoder -> 'b decoder

val field : string -> 'a decoder -> 'a decoder

val reqField : string -> 'a decoder -> ('a -> 'b) decoder -> 'b decoder

val optField : string -> 'a decoder -> ('a option -> 'b) decoder -> 'b decoder

val dfltField : string -> 'a decoder -> 'a -> ('a -> 'b) decoder -> 'b decoder

val array : 'a decoder -> 'a list decoder
val sub : int -> 'a decoder -> 'a decoder

val at : JSONUtil.path -> 'a decoder -> 'a decoder

val succeed : 'a -> 'a decoder

val fail : string -> 'a decoder

val andThen : ('a -> 'b decoder) -> 'a decoder -> 'b decoder

val orElse : 'a decoder * 'a decoder -> 'a decoder

val choose : 'a decoder list -> 'a decoder

val map : ('a -> 'b) -> 'a decoder -> 'b decoder
val map2 : ('a * 'b -> 'res)
  -> ('a decoder * 'b decoder)
  -> 'res decoder
val map3 : ('a * 'b * 'c -> 'res)
  -> ('a decoder * 'b decoder * 'c decoder)
  -> 'res decoder
val map4 : ('a * 'b * 'c * 'd -> 'res)
  -> ('a decoder * 'b decoder * 'c decoder * 'd decoder)
  -> 'res decoder

val tuple2 : ('a decoder * 'b decoder) -> ('a * 'b) decoder
val tuple3 : ('a decoder * 'b decoder * 'c decoder) -> ('a * 'b * 'c) decoder
val tuple4 : ('a decoder * 'b decoder * 'c decoder * 'd decoder)
  -> ('a * 'b * 'c * 'd) decoder

val delay : (unit -> 'a decoder) -> 'a decoder

Description

exception JSONError of exn * JSON.value

raised when an error is detected during processing of a JSON value. The first argument, which is one of the exceptions described below, details the type of error and the second argument is the value that was being processed at the point of the error.

exception NotNull of JSON.value

used by the null decoder when the argument is not the JSON null value.

exception NotBool of JSON.value

used by the bool decode when the argument is not a JSON boolean. This exception is the same as JSONUtil.NotBool.

exception NotInt of JSON.value

used by the int and intInf decoders when the argument is not a JSON integer number. This exception is the same as JSONUtil.NotInt.

exception NotNumber of JSON.value

used by the number decoder when the argument is not a JSON number. This exception is the same as JSONUtil.NotNumber.

exception NotString of JSON.value

used by the string decoder when the argument is not a JSON string. This exception is the same as JSONUtil.NotString.

exception NotObject of JSON.value

used by the field decoder when the argument is not a JSON object. This exception is the same as JSONUtil.NotObject.

exception FieldNotFound of JSON.value * string

This exception is used by the field decoder when the given field is not found in an object. This exception is the same as JSONUtil.FieldNotFound.

exception NotArray of JSON.value

This exception is used by the array decoder when the argument is not a JSON array. This exception is the same as JSONUtil.NotArray.

exception ArrayBounds of JSON.value * int

This exception is used when access to an array value is out of bounds. This exception is the same as JSONUtil.ArrayBounds.

val exnMessage : exn -> string

exnMessage exn returns an error-message string for the exception value exn. This function produces specialized messages for the JSONError wrapped around the other exceptions defined in this structure (or the Fail exception). It falls back to the General.exnMessage function for other exceptions.

type 'a decoder'

the type of a decoder that decodes a JSON value to a value of type 'a.

val decode : 'a decoder -> JSON.value -> 'a

decode d jv decodes the JSON value jv using the decoder d. Failure to decode will be signaled by raising an exception that depends on the decoder and value.

val decodeString : 'a decoder -> string -> 'a

decode d s decodes the JSON value that results from parsing the string s.

val decodeFile : 'a decoder -> string -> 'a

decode d f decodes the JSON value that results from parsing the file f.

val bool : bool decoder

decodes a JSON Boolean value. This decoder raises the exception value JSONError(NotBool, jv) if the value jv is not a JSON Boolean.

val int : int decoder

decodes a JSON integer value. This decoder raises the exception value JSONError(NotInt, jv) if the argument jv is not a JSON integer value and the Overflow exception if the integer is too large to be represented as an Int.int.

val intInf : IntInf.int decoder

decodes a JSON integer value. This decoder raises the exception value JSONError(NotInt, jv) if the argument jv is not a JSON integer value.

val number : Real64.real decoder

decodes a JSON number value. This decoder raises the exception value JSONError(NotNumber, jv) if the value jv is not a JSON number.

val string : string decoder

decodes a JSON string value. This decoder raises the exception value JSONError(NotString, jv) if the argument jv is not a JSON string.

val null : 'a -> 'a decoder

null v returns a decoder for the JSON null value. When used to decode a null value, it will return its argument v; otherwise it will raise the exception value JSONError(NotNull, jv) when the argument jv is not a JSON null value.

val raw : JSON.value decoder

this decoder returns the raw JSON value that it is applied to (i.e., it is the identity decoder).

val nullable : 'a decoder -> 'a option decoder

nullable d returns a decoder that maps null to NONE and otherwise applies SOME to the result of decoding the value using the decoder d.

val try : 'a decoder -> 'a option decoder

try d returns a decoder that attempts to decode its argument using the decoder d. If it fails, then NONE is returned. Otherwise, SOME is applied to the result od decoding the value.

val seq : 'a decoder → ('a -> 'b) decoder -> 'b decoder

seq d k sequences decoding operations in a continuation-passing style.

val field : string -> 'a decoder -> 'a decoder

field lab d returns a decoder that decodes the object field with the label lab using the decoder d. It will raise the exception value JSONError(NotObject, v) when the argument v is not a JSON object and the exception value JSONError(FieldNotFound lab, v), when v does not have a field with the specified label.

val reqField : string -> 'a decoder -> ('a -> 'b) decoder -> 'b decoder

reqField lab d k returns a decoder for a required object field that can be sequenced in a continuation-passing style (it is equivalent to seq (field lab d) k). It will raise the exception value JSONError(NotObject, v) when the argument v is not a JSON object and the exception value JSONError(FieldNotFound lab, v) when v does not have a field with the specified label.

val optField : string -> 'a decoder -> ('a option -> 'b) decoder -> 'b decoder

optField lab d k returns a decoder for an optional object field that can be sequenced in a continuation-passing style. If the field is not present in the object, then NONE is passed to k.

val dfltField : string -> 'a decoder -> 'a -> ('a -> 'b) decoder -> 'b decoder

dfltField lab d dflt k returns a decoder for an optional object field that can be sequenced in a continuation-passing style. If the field is not present in the object, then dflt is passed to k.

val array : 'a decoder -> 'a list decoder

array d returns a decoder that when applied to a JSON array, will decode the elements of the array using the decoder d and return the result as a list. It raises the exception value JSONError(NotArray, jv) if the argument jv is not a JSON array.

val sub : int -> 'a decoder -> 'a decoder

sub i d returns a decoder that when given a JSON array, decodes the i'th element of the array using the decoder d. This decoder will raise the exception value JSONError(NotArray, jv) if the argument jv is not a JSON array, and the exception value JSONError(ArrayBounds i, jv) if the index i is out of bounds for the array.

val at : JSONUtil.path -> 'a decoder -> 'a decoder

at path d returns a decoder that uses the path to select a value from its argument (see JSONUtil.get) and then decodes that value using the decoder d.

val succeed : 'a -> 'a decoder

succeed v returns a decoder that always yields v for any argument.

val fail : string -> 'a decoder

fail msg returns a decoder that raises JSONError(Fail msg, jv) for any JSON input jv.

val andThen : ('a -> 'b decoder) -> 'a decoder -> 'b decoder

andThen f d returns a decoder that first uses d to decode a value v from its argument and then returns the result of applying f to v.

val orElse : 'a decoder * 'a decoder -> 'a decoder

orElse (d1, d2) returns a decoder that tries to decode its argument using the decoder d1` and, if that fails, tries to decode the argument using d2.

val choose : 'a decoder list -> 'a decoder

choose ds returns a decoder that tries to decode its argument using each of the decoders in the list ds, returning the first successful result. If all of the decoders fail, then the exception value JSONError(Fail "no choice", jv) is raised, where jv is the JSON value being decoded. The expression choose [d1, …​, dn] is equivalent to

orElse(d1, orElse(d2, ..., orElse(dn, fail "no choice") ... ))
val map : ('a -> 'b) -> 'a decoder -> 'b decoder

map f d returns a decoder that applies the function f to the result of decoding a JSON value using the decoder d.

val map2 : ('a * 'b -> 'res) -> …​ -> 'res decoder
val map3 : ('a * 'b * 'c -> 'res) -> …​ -> 'res decoder
val map4 : ('a * 'b * 'c * 'd -> 'res) -> …​ -> 'res decoder
val tuple2 : ('a decoder * 'b decoder) -> ('a * 'b) decoder

tuple2 (d1, d2) is equivalent to map2 Fn.id (d1, d2).

val tuple3 : ('a decoder * 'b decoder * 'c decoder) -> ('a * 'b * 'c) decoder

tuple3 (d1, d2, d3) is equivalent to map2 Fn.id (d1, d2, d3).

val tuple4 : ('a decoder * 'b decoder * 'c decoder * 'd decoder) -> ('a * 'b * 'c * 'd) decoder

tuple4 (d1, d2, d3, d4) is equivalent to map4 Fn.id (d1, d2, d3, d4).

val delay : (unit -> 'a decoder) -> 'a decoder

delay f returns a decoder that delays the application of f to produce the decoder and can be used to define recursive decoders. The expression delay f is equivalent to andThen f (succeed ()).

Discussion

A number of these combinators work best when composed using a infix pipe operator. For example:

fun |> (x, f) = f x
infix |>

val d = succeed (fn (n : string) => fn (a : int) => {name=n, age=a})
        |> reqField "name" string
        |> reqField "age" int