package decoders-sexplib

  1. Overview
  2. Docs

Module Decoders_sexplib.DecodeSource

Turn S-expressions into Ocaml values via Sexplib.

Following the convention of Sexplib0.Sexp_conv.hashtbl_of_sexp, we consider an S-expression to be an "object" if it is a list of two-element lists. For example:

((field1 value1) (field2 (value2 value3)))

Following `dune` conventions, we also allow as "objects" S-expressions like:

((field1 value1) (field2 value2 value3))

These two S-expressions will be treated in the same way by the object combinators below (e.g. field).

Like YAML, fields of an object are not necessarily atoms. To handle these, look for the primed combinators (e.g. keys').

include Decoders.Decode.S with type value = Sexplib0.Sexp.t

The type of values to be decoded (e.g. JSON or Yaml).

Sourceval pp_error : Format.formatter -> error -> unit
Sourceval string_of_error : error -> string
Sourceval of_string : string -> (value, error) Decoders.Decode.result
Sourceval of_file : string -> (value, error) Decoders.Decode.result
Sourcetype 'a decoder

The type of decoders.

Use the functions below to construct decoders for your data types.

To run a decoder, pass it to decode_value.

Primitives

Sourceval string : string decoder

Decode a string.

Sourceval int : int decoder

Decode an int.

Sourceval float : float decoder

Decode a float.

Sourceval bool : bool decoder

Decode a bool.

Sourceval null : unit decoder

Decode a null.

Sourceval value : value decoder

Decode a literal value.

Lists

Sourceval list : 'a decoder -> 'a list decoder

Decode a collection into an OCaml list.

Sourceval list_filter : 'a option decoder -> 'a list decoder

Decode a collection into an OCaml list, skipping elements for which the decoder returns None.

Sourceval list_fold_left : ('a -> 'a decoder) -> 'a -> 'a decoder

Decode a collection with an accumulator.

If we consider that an 'a decoder is basically a type alias for json -> ('a, error) result, the signature of this function is comparable to that of List.fold_left:

val List.fold_left : ('a ->   'b ->                 'a) -> 'a -> 'b list ->                 'a
val list_fold_left : ('a -> json -> ('a, error) result) -> 'a ->    json -> ('a, error) result
val list_fold_left : ('a ->                 'a decoder) -> 'a ->                    'a decoder
Sourceval array : 'a decoder -> 'a array decoder

Decode a collection into an OCaml array.

Sourceval index : int -> 'a decoder -> 'a decoder

Decode a collection, requiring a particular index.

Sourceval uncons : ('a -> 'b decoder) -> 'a decoder -> 'b decoder

fst |> uncons rest decodes the first element of a list using fst, then decodes the remainder of the list using rest.

For example, to decode this s-expression:

    (library
      (name decoders))

we can use this decoder:

    string |> uncons (function
      | "library" -> field "name" string
      | _ -> fail "Expected a library stanza")

As another example, say you have a JSON array that starts with a string, then a bool, then a list of integers:

    ["hello", true, 1, 2, 3, 4]

We could decode it like this:

    let (>>=::) fst rest = uncons rest fst

    let decoder : (string * bool * int list) decoder =
      string >>=:: fun the_string ->
      bool >>=:: fun the_bool ->
      list int >>= fun the_ints ->
      succeed (the_string, the_bool, the_ints)

(If you squint, the uncons operator >>=:: kind of looks like the cons operator ::.)

Object primitives

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

Decode an object, requiring a particular field.

Sourceval field_opt : string -> 'a decoder -> 'a option decoder

Decode an object, where a particular field may or may not be present.

For example, (field_opt "hello" int):

  • when run on {"hello": 123}, will succeed with Some 123
  • when run on {"hello": null}, will fail
  • when run on {"world": 123}, will succeed with None
  • when run on ["a", "list", "of", "strings"], will fail
Sourceval field_opt_or : default:'a -> string -> 'a decoder -> 'a decoder

Similar to field_opt but with a default value.

  • since 0.7
Sourceval single_field : (string -> 'a decoder) -> 'a decoder

Decode an object, requiring exactly one field.

Sourceval at : string list -> 'a decoder -> 'a decoder

Decode a nested object, requiring certain fields.

Inconsistent structure

Sourceval maybe : 'a decoder -> 'a option decoder

maybe d is a decoder that always succeeds. If d succeeds with x, then maybe d succeeds with Some x, otherwise if d fails, then maybe d succeeds with None.

For example, maybe (field "hello" int):

  • when run on {"hello": 123}, will succeed with Some 123
  • when run on {"hello": null}, will succeed with None
  • when run on {"world": 123}, will succeed with None
  • when run on ["a", "list", "of", "strings"], will succeed with None
Sourceval nullable : 'a decoder -> 'a option decoder

nullable d will succeed with None if the JSON value is null. If the JSON value is non-null, it wraps the result of running x in a Some.

For example, field "hello" (nullable int):

  • when run on {"hello": 123}, will succeed with Some 123
  • when run on {"hello": null}, will succeed with None
  • when run on {"world": 123}, will fail
  • when run on ["a", "list", "of", "strings"], will fail
Sourceval one_of : (string * 'a decoder) list -> 'a decoder

Try a sequence of different decoders.

Sourceval pick : (string * 'a decoder decoder) list -> 'a decoder

pick choices picks a single choice, like one_of. However, each element of choices can look at the value, decide if it applies (e.g. based on the value of a single field, like a "kind" or "type" field), and if it does, returns a decoder for the rest of the value.

If a choice is made, even if the returned sub-decoder fails, the error message will totally ignore the rest of the choices and only be about the choice that was initially made.

  • since 0.7
Sourceval decode_sub : value -> 'a decoder -> 'a decoder

decode_sub value sub_dec uses sub_dec to decode value. This is useful when one has a value on hand.

  • since 0.7

Mapping

Sourceval map : ('a -> 'b) -> 'a decoder -> 'b decoder

Map over the result of a decoder.

Sourceval apply : ('a -> 'b) decoder -> 'a decoder -> 'b decoder

Try two decoders and then combine the result. We can use this to decode objects with many fields (but it's preferable to use Infix.(>>=) - see the README).

Working with object keys

Sourceval keys : string list decoder

Decode all of the keys of an object to a list of strings.

Sourceval key_value_pairs : 'v decoder -> (string * 'v) list decoder

Decode an object into a list of key-value pairs.

Sourceval key_value_pairs_seq : (string -> 'v decoder) -> 'v list decoder

Decode an object into a list of values, where the value decoder depends on the key.

Sourceval keys' : 'k decoder -> 'k list decoder

keys' is for when your keys might not be strings - probably only likely for Yaml.

Sourceval key_value_pairs' : 'k decoder -> 'v decoder -> ('k * 'v) list decoder
Sourceval key_value_pairs_seq' : 'k decoder -> ('k -> 'v decoder) -> 'v list decoder

Fancy decoding

Sourceval succeed : 'a -> 'a decoder

A decoder that always succeeds with the argument, ignoring the input.

Sourceval fail : string -> 'a decoder

A decoder that always fails with the given message, ignoring the input.

Sourceval fail_with : error -> 'a decoder
Sourceval from_result : ('a, error) Decoders.Decode.result -> 'a decoder
Sourceval and_then : ('a -> 'b decoder) -> 'a decoder -> 'b decoder

Create decoders that depend on previous results.

Sourceval fix : ('a decoder -> 'a decoder) -> 'a decoder

Recursive decoders.

let my_decoder = fix (fun my_decoder -> ...) allows you to define my_decoder in terms of itself.

Sourceval of_of_string : msg:string -> (string -> 'a option) -> 'a decoder

Create a decoder from a function of_string : string -> 'a option

Sourcemodule Infix : sig ... end
include module type of Infix
Sourceval (>|=) : 'a decoder -> ('a -> 'b) -> 'b decoder
Sourceval (>>=) : 'a decoder -> ('a -> 'b decoder) -> 'b decoder
Sourceval (<*>) : ('a -> 'b) decoder -> 'a decoder -> 'b decoder
Sourceval (<$>) : ('a -> 'b) -> 'a decoder -> 'b decoder
Sourceval (let+) : 'a decoder -> ('a -> 'b) -> 'b decoder
Sourceval (and+) : 'a decoder -> 'b decoder -> ('a * 'b) decoder
Sourceval (let*) : 'a decoder -> ('a -> 'b decoder) -> 'b decoder
Sourceval (and*) : 'a decoder -> 'b decoder -> ('a * 'b) decoder

Running decoders

Sourceval decode_value : 'a decoder -> value -> ('a, error) Decoders.Decode.result

Run a decoder on some input.

Sourceval decode_string : 'a decoder -> string -> ('a, error) Decoders.Decode.result

Run a decoder on a string.

Sourceval decode_file : 'a decoder -> string -> ('a, error) Decoders.Decode.result

Run a decoder on a file.

Sourcemodule Pipeline : sig ... end
OCaml

Innovation. Community. Security.