gleam/dynamic

Types

Error returned when unexpected data is encountered

pub type DecodeError {
  DecodeError(
    expected: String,
    found: String,
    path: List(String),
  )
}

Constructors

  • DecodeError(expected: String, found: String, path: List(String))
pub type DecodeErrors =
  List(DecodeError)
pub type Decoder(t) =
  fn(Dynamic) -> Result(t, DecodeErrors)

Dynamic data is data that we don’t know the type of yet. We likely get data like this from interop with Erlang, or from IO with the outside world.

pub external type Dynamic

Functions

pub fn any(of decoders: List(
    fn(Dynamic) -> Result(a, List(DecodeError)),
  )) -> fn(Dynamic) -> Result(a, List(DecodeError))

Joins multiple decoders into one. When run they will each be tried in turn until one succeeds, or they all fail.

Examples

> import gleam/result
> let bool_or_string = any(of: [
>   string,
>   fn(x) { result.map(bool(x), fn(_) { "a bool" }) }
> ])
> bool_or_string(from("ok"))
Ok("ok")

> bool_or_string(from(True))
Ok("a bool")

> bool_or_string(from(1))
Error(DecodeError(expected: "unknown", found: "unknown", path: []))
pub fn bit_string(from data: Dynamic) -> Result(
  BitString,
  List(DecodeError),
)

Checks to see whether a Dynamic value is a bit_string, and returns that bit string if it is.

Examples

> bit_string(from("Hello")) == bit_string.from_string("Hello")
True

> bit_string(from(123))
Error([DecodeError(expected: "BitString", found: "Int", path: [])])
pub fn bool(from data: Dynamic) -> Result(Bool, List(DecodeError))

Checks to see whether a Dynamic value is a bool, and returns that bool if it is.

Examples

> bool(from(True))
Ok(True)

> bool(from(123))
Error([DecodeError(expected: "bool", found: "Int", path: [])])
pub fn classify(data: Dynamic) -> String

Return a string indicating the type of the dynamic value.

> classify(from("Hello"))
"String"
pub fn decode2(constructor: fn(a, b) -> c, t1: fn(Dynamic) ->
    Result(a, List(DecodeError)), t2: fn(Dynamic) ->
    Result(b, List(DecodeError))) -> fn(Dynamic) ->
  Result(c, List(DecodeError))

Decode 2 values from a Dynamic value.

Examples

> from(#(1, 2.0, "3"))
> |> decode2(MyRecord, element(0, int), element(1, float))
Ok(MyRecord(1, 2.0))
> from(#("", "", ""))
> |> decode2(MyRecord, element(0, int), element(1, float))
Error([
  DecodeError(expected: "Int", found: "String", path: ["0"]),
  DecodeError(expected: "Float", found: "String", path: ["1"]),
])
pub fn decode3(constructor: fn(a, b, c) -> d, t1: fn(Dynamic) ->
    Result(a, List(DecodeError)), t2: fn(Dynamic) ->
    Result(b, List(DecodeError)), t3: fn(Dynamic) ->
    Result(c, List(DecodeError))) -> fn(Dynamic) ->
  Result(d, List(DecodeError))

Decode 3 values from a Dynamic value.

Examples

> from(#(1, 2.0, "3"))
> |> decode3(MyRecord, element(0, int), element(1, float), element(2, string))
Ok(MyRecord(1, 2.0, "3"))
> from(#("", "", ""))
> |> decode3(MyRecord, element(0, int), element(1, float), element(2, string))
Error([
  DecodeError(expected: "Int", found: "String", path: ["0"]),
  DecodeError(expected: "Float", found: "String", path: ["1"]),
])
pub fn decode4(constructor: fn(a, b, c, d) -> e, t1: fn(Dynamic) ->
    Result(a, List(DecodeError)), t2: fn(Dynamic) ->
    Result(b, List(DecodeError)), t3: fn(Dynamic) ->
    Result(c, List(DecodeError)), t4: fn(Dynamic) ->
    Result(d, List(DecodeError))) -> fn(Dynamic) ->
  Result(e, List(DecodeError))

Decode 4 values from a Dynamic value.

Examples

> from(#(1, 2.1, "3", "4"))
> |> decode4(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
> )
Ok(MyRecord(1, 2.1, "3", "4"))
> from(#("", "", "", ""))
> |> decode4(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
> )
Error([
  DecodeError(expected: "Int", found: "String", path: ["0"]),
  DecodeError(expected: "Float", found: "String", path: ["1"]),
])
pub fn decode5(constructor: fn(a, b, c, d, e) -> f, t1: fn(
    Dynamic,
  ) -> Result(a, List(DecodeError)), t2: fn(Dynamic) ->
    Result(b, List(DecodeError)), t3: fn(Dynamic) ->
    Result(c, List(DecodeError)), t4: fn(Dynamic) ->
    Result(d, List(DecodeError)), t5: fn(Dynamic) ->
    Result(e, List(DecodeError))) -> fn(Dynamic) ->
  Result(f, List(DecodeError))

Decode 5 values from a Dynamic value.

Examples

> from(#(1, 2.1, "3", "4", "5"))
> |> decode5(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
> )
Ok(MyRecord(1, 2.1, "3", "4", "5"))
> from(#("", "", "", "", ""))
> |> decode5(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
> )
Error([
  DecodeError(expected: "Int", found: "String", path: ["0"]),
  DecodeError(expected: "Float", found: "String", path: ["1"]),
])
pub fn decode6(constructor: fn(a, b, c, d, e, f) -> g, t1: fn(
    Dynamic,
  ) -> Result(a, List(DecodeError)), t2: fn(Dynamic) ->
    Result(b, List(DecodeError)), t3: fn(Dynamic) ->
    Result(c, List(DecodeError)), t4: fn(Dynamic) ->
    Result(d, List(DecodeError)), t5: fn(Dynamic) ->
    Result(e, List(DecodeError)), t6: fn(Dynamic) ->
    Result(f, List(DecodeError))) -> fn(Dynamic) ->
  Result(g, List(DecodeError))

Decode 6 values from a Dynamic value.

Examples

> from(#(1, 2.1, "3", "4", "5", "6"))
> |> decode6(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
>   element(5, string),
> )
Ok(MyRecord(1, 2.1, "3", "4", "5", "6"))
> from(#("", "", "", "", "", ""))
> |> decode6(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
>   element(5, string),
> )
Error([
  DecodeError(expected: "Int", found: "String", path: ["0"]),
  DecodeError(expected: "Float", found: "String", path: ["1"]),
])
pub fn decode7(constructor: fn(a, b, c, d, e, f, g) -> h, t1: fn(
    Dynamic,
  ) -> Result(a, List(DecodeError)), t2: fn(Dynamic) ->
    Result(b, List(DecodeError)), t3: fn(Dynamic) ->
    Result(c, List(DecodeError)), t4: fn(Dynamic) ->
    Result(d, List(DecodeError)), t5: fn(Dynamic) ->
    Result(e, List(DecodeError)), t6: fn(Dynamic) ->
    Result(f, List(DecodeError)), t7: fn(Dynamic) ->
    Result(g, List(DecodeError))) -> fn(Dynamic) ->
  Result(h, List(DecodeError))

Decode 7 values from a Dynamic value.

Examples

> from(#(1, 2.1, "3", "4", "5", "6"))
> |> decode7(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
>   element(5, string),
>   element(6, string),
> )
Ok(MyRecord(1, 2.1, "3", "4", "5", "6", "7"))
> from(#("", "", "", "", "", "", ""))
> |> decode7(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
>   element(5, string),
>   element(6, string),
> )
Error([
  DecodeError(expected: "Int", found: "String", path: ["0"]),
  DecodeError(expected: "Float", found: "String", path: ["1"]),
])
pub fn decode8(constructor: fn(a, b, c, d, e, f, g, h) -> i, t1: fn(
    Dynamic,
  ) -> Result(a, List(DecodeError)), t2: fn(Dynamic) ->
    Result(b, List(DecodeError)), t3: fn(Dynamic) ->
    Result(c, List(DecodeError)), t4: fn(Dynamic) ->
    Result(d, List(DecodeError)), t5: fn(Dynamic) ->
    Result(e, List(DecodeError)), t6: fn(Dynamic) ->
    Result(f, List(DecodeError)), t7: fn(Dynamic) ->
    Result(g, List(DecodeError)), t8: fn(Dynamic) ->
    Result(h, List(DecodeError))) -> fn(Dynamic) ->
  Result(i, List(DecodeError))

Decode 8 values from a Dynamic value.

Examples

> from(#(1, 2.1, "3", "4", "5", "6", "7", "8"))
> |> decode7(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
>   element(5, string),
>   element(6, string),
>   element(7, string),
> )
Ok(MyRecord(1, 2.1, "3", "4", "5", "6", "7", "8"))
> from(#("", "", "", "", "", "", "", ""))
> |> decode7(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
>   element(5, string),
>   element(6, string),
>   element(7, string),
> )
Error([
  DecodeError(expected: "Int", found: "String", path: ["0"]),
  DecodeError(expected: "Float", found: "String", path: ["1"]),
])
pub fn decode9(constructor: fn(a, b, c, d, e, f, g, h, i) -> j, t1: fn(
    Dynamic,
  ) -> Result(a, List(DecodeError)), t2: fn(Dynamic) ->
    Result(b, List(DecodeError)), t3: fn(Dynamic) ->
    Result(c, List(DecodeError)), t4: fn(Dynamic) ->
    Result(d, List(DecodeError)), t5: fn(Dynamic) ->
    Result(e, List(DecodeError)), t6: fn(Dynamic) ->
    Result(f, List(DecodeError)), t7: fn(Dynamic) ->
    Result(g, List(DecodeError)), t8: fn(Dynamic) ->
    Result(h, List(DecodeError)), t9: fn(Dynamic) ->
    Result(i, List(DecodeError))) -> fn(Dynamic) ->
  Result(j, List(DecodeError))

Decode 9 values from a Dynamic value.

Examples

> from(#(1, 2.1, "3", "4", "5", "6", "7", "8", "9"))
> |> decode7(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
>   element(5, string),
>   element(6, string),
>   element(7, string),
>   element(8, string),
> )
Ok(MyRecord(1, 2.1, "3", "4", "5", "6", "7", "8", "9"))
> from(#("", "", "", "", "", "", "", "", ""))
> |> decode7(
>   MyRecord,
>   element(0, int),
>   element(1, float),
>   element(2, string),
>   element(3, string),
>   element(4, string),
>   element(5, string),
>   element(6, string),
>   element(7, string),
>   element(8, string),
> )
Error([
  DecodeError(expected: "Int", found: "String", path: ["0"]),
  DecodeError(expected: "Float", found: "String", path: ["1"]),
])
pub fn dynamic(value: Dynamic) -> Result(
  Dynamic,
  List(DecodeError),
)

Decodes a Dynamic value from a Dynamic value.

This function doesn’t seem very useful at first, but it can be convenient when you need to give a decoder function but you don’t actually care what the to-decode value is.

pub fn element(at index: Int, of inner_type: fn(Dynamic) ->
    Result(a, List(DecodeError))) -> fn(Dynamic) ->
  Result(a, List(DecodeError))

Checks to see if a Dynamic value is a tuple large enough to have a certain index, and returns the value of that index if it is.

Examples

> from(#(1, 2))
> |> element(0, int)
Ok(from(1))
> from(#(1, 2))
> |> element(2, int)
Error([
  DecodeError(
    expected: "Tuple of at least 3 elements",
    found: "Tuple of 2 elements",
    path: [],
  ),
])
pub fn field(named name: a, of inner_type: fn(Dynamic) ->
    Result(b, List(DecodeError))) -> fn(Dynamic) ->
  Result(b, List(DecodeError))

Checks to see if a Dynamic value is a map with a specific field, and returns the value of that field if it is.

This will not succeed on a record.

Examples

> import gleam/map
> from(map.new("Hello", "World"))
> |> field(named: "Hello", of: string)
Ok("World")

> from(123)
> |> field("Hello", string)
Error([DecodeError(expected: "Map", found: "Int", path: [])])
pub fn float(from data: Dynamic) -> Result(
  Float,
  List(DecodeError),
)

Checks to see whether a Dynamic value is a float, and returns that float if it is.

Examples

> float(from(2.0))
Ok(2.0)

> float(from(123))
Error([DecodeError(expected: "Float", found: "Int", path: [])])
pub fn from(a: a) -> Dynamic

Converts any Gleam data into Dynamic data.

pub fn int(from data: Dynamic) -> Result(Int, List(DecodeError))

Checks to see whether a Dynamic value is an int, and returns that int if it is.

Examples

> int(from(123))
Ok(123)

> int(from("Hello"))
Error([DecodeError(expected: "Int", found: "String", path: [])])
pub fn list(of decoder_type: fn(Dynamic) ->
    Result(a, List(DecodeError))) -> fn(Dynamic) ->
  Result(List(a), List(DecodeError))

Checks to see whether a Dynamic value is a list of a particular type, and returns that list if it is.

The second argument is a decoder function used to decode the elements of the list. The list is only decoded if all elements in the list can be successfully decoded using this function.

If you do not wish to decode all the elements in the list use the shallow_list function instead.

Examples

> from(["a", "b", "c"])
> |> list(of: string)
Ok(["a", "b", "c"])

> from([1, 2, 3])
> |> list(of: string)
Error([DecodeError(expected: "String", found: "Int", path: [])])

> from("ok")
> |> list(of: string)
Error([DecodeError(expected: "List", found: "String", path: [])])
pub fn map(of key_type: fn(Dynamic) ->
    Result(a, List(DecodeError)), to value_type: fn(Dynamic) ->
    Result(b, List(DecodeError))) -> fn(Dynamic) ->
  Result(Map(a, b), List(DecodeError))

Checks to see if a Dynamic value is a map.

Examples

> import gleam/map

> map.new() |> from |> map(string, int)
Ok(map.new())

> from(1) |> map(string, int)
Error(DecodeError(expected: "Map", found: "Int", path: []))

> from("") |> map(string, int)
Error(DecodeError(expected: "Map", found: "String", path: []))
pub fn optional(of decode: fn(Dynamic) ->
    Result(a, List(DecodeError))) -> fn(Dynamic) ->
  Result(Option(a), List(DecodeError))

Checks to see if a Dynamic value is a nullable version of a particular type, and returns a corresponding Option if it is.

Examples

> from("Hello")
> |> option(string)
Ok(Some("Hello"))

> from("Hello")
> |> option(string)
Ok(Some("Hello"))

> from(atom.from_string("null"))
> |> option(string)
Ok(None)

> from(atom.from_string("nil"))
> |> option(string)
Ok(None)

> from(atom.from_string("undefined"))
> |> option(string)
Ok(None)

> from(123)
> |> option(string)
Error([DecodeError(expected: "BitString", found: "Int", path: [])])
```gleam
pub fn result(ok decode_ok: fn(Dynamic) ->
    Result(a, List(DecodeError)), error decode_error: fn(Dynamic) ->
    Result(b, List(DecodeError))) -> fn(Dynamic) ->
  Result(Result(a, b), List(DecodeError))

Checks to see whether a Dynamic value is a result of a particular type, and returns that result if it is.

The ok and error arguments are decoders for decoding the Ok and Error values of the result.

Examples

> from(Ok(1))
> |> result(ok: int, error: string)
Ok(Ok(1))

> from(Error("boom"))
> |> result(ok: int, error: string)
Ok(Error("boom"))

> from(123)
> |> result(ok: int, error: string)
Error([DecodeError(expected: "2 element tuple", found: "Int", path: [])])
pub fn shallow_list(from value: Dynamic) -> Result(
  List(Dynamic),
  List(DecodeError),
)

Checks to see whether a Dynamic value is a list, and returns that list if it is. The types of the elements are not checked.

If you wish to decode all the elements in the list use the list function instead.

Examples

> shallow_list(from(["a", "b", "c"]))
Ok([from("a"), from("b"), from("c")])

> shallow_list(1)
Error([DecodeError(expected: "Int", found: "Int", path: [])])
pub fn string(from data: Dynamic) -> Result(
  String,
  List(DecodeError),
)

Checks to see whether a Dynamic value is a string, and returns that string if it is.

Examples

> string(from("Hello"))
Ok("Hello")

> string(from(123))
Error([DecodeError(expected: "String", found: "Int", path: [])])
pub fn tuple2(first decode1: fn(Dynamic) ->
    Result(a, List(DecodeError)), second decode2: fn(Dynamic) ->
    Result(b, List(DecodeError))) -> fn(Dynamic) ->
  Result(#(a, b), List(DecodeError))

Checks to see if a Dynamic value is a 2 element tuple containing specifically typed elements.

Examples

> from(#(1, 2))
> |> tuple2(int, int)
Ok(#(1, 2))

> from(#(1, 2.0))
> |> tuple2(int, float)
Ok(#(1, 2.0))

> from(#(1, 2, 3))
> |> tuple2(int, float)
Error([
  DecodeError(expected: "2 element tuple", found: "3 element tuple", path: []),
])

> from("")
> |> tuple2(int, float)
Error([DecodeError(expected: "2 element tuple", found: "String", path: [])])
pub fn tuple3(first decode1: fn(Dynamic) ->
    Result(a, List(DecodeError)), second decode2: fn(Dynamic) ->
    Result(b, List(DecodeError)), third decode3: fn(Dynamic) ->
    Result(c, List(DecodeError))) -> fn(Dynamic) ->
  Result(#(a, b, c), List(DecodeError))

Checks to see if a Dynamic value is a 3-element tuple containing specifically typed elements.

Examples

> from(#(1, 2, 3))
> |> tuple3(int, int, int)
Ok(#(1, 2, 3))

> from(#(1, 2.0, "3"))
> |> tuple3(int, float, string)
Ok(#(1, 2.0, "3"))

> from(#(1, 2))
> |> tuple3(int, float, string)
Error([
  DecodeError(expected: "3 element tuple", found: "2 element tuple", path: [])),
])

> from("")
> |> tuple3(int, float, string)
Error([
  DecodeError(expected: "3 element tuple", found: "String", path: []),
])
pub fn tuple4(first decode1: fn(Dynamic) ->
    Result(a, List(DecodeError)), second decode2: fn(Dynamic) ->
    Result(b, List(DecodeError)), third decode3: fn(Dynamic) ->
    Result(c, List(DecodeError)), fourth decode4: fn(Dynamic) ->
    Result(d, List(DecodeError))) -> fn(Dynamic) ->
  Result(#(a, b, c, d), List(DecodeError))

Checks to see if a Dynamic value is a 4 element tuple containing specifically typed elements.

Examples

> from(#(1, 2, 3, 4))
> |> tuple4(int, int, int, int)
Ok(#(1, 2, 3, 4))

> from(#(1, 2.0, "3", 4))
> |> tuple4(int, float, string, int)
Ok(#(1, 2.0, "3", 4))

> from(#(1, 2))
> |> tuple4(int, float, string, int)
Error([
  DecodeError(expected: "4 element tuple", found: "2 element tuple", path: []),
])

> from("")
> |> tuple4(int, float, string, int)
Error([
  DecodeError(expected: "4 element tuple", found: "String", path: []),
])
pub fn tuple5(first decode1: fn(Dynamic) ->
    Result(a, List(DecodeError)), second decode2: fn(Dynamic) ->
    Result(b, List(DecodeError)), third decode3: fn(Dynamic) ->
    Result(c, List(DecodeError)), fourth decode4: fn(Dynamic) ->
    Result(d, List(DecodeError)), fifth decode5: fn(Dynamic) ->
    Result(e, List(DecodeError))) -> fn(Dynamic) ->
  Result(#(a, b, c, d, e), List(DecodeError))

Checks to see if a Dynamic value is a 5-element tuple containing specifically typed elements.

Examples

> from(#(1, 2, 3, 4, 5))
> |> tuple5(int, int, int, int, int)
Ok(#(1, 2, 3, 4, 5))

> from(#(1, 2.0, "3", 4, 5))
> |> tuple5(int, float, string, int, int)
Ok(#(1, 2.0, "3", 4, 5))

> from(#(1, 2))
> |> tuple5(int, float, string, int, int)
Error([
  DecodeError(expected: "5 element tuple", found: "2 element tuple", path: [])),
])

> from("")
> |> tuple5(int, float, string, int, int)
Error([DecodeError(expected: "5 element tuple", found: "String", path: [])])
pub fn tuple6(first decode1: fn(Dynamic) ->
    Result(a, List(DecodeError)), second decode2: fn(Dynamic) ->
    Result(b, List(DecodeError)), third decode3: fn(Dynamic) ->
    Result(c, List(DecodeError)), fourth decode4: fn(Dynamic) ->
    Result(d, List(DecodeError)), fifth decode5: fn(Dynamic) ->
    Result(e, List(DecodeError)), sixth decode6: fn(Dynamic) ->
    Result(f, List(DecodeError))) -> fn(Dynamic) ->
  Result(#(a, b, c, d, e, f), List(DecodeError))

Checks to see if a Dynamic value is a 6-element tuple containing specifically typed elements.

Examples

> from(#(1, 2, 3, 4, 5, 6)) 
> |> tuple6(int, int, int, int, int, int)
Ok(#(1, 2, 3, 4, 5, 6))

> from(#(1, 2.0, "3", 4, 5, 6))
> |> tuple6(int, float, string, int, int)
Ok(#(1, 2.0, "3", 4, 5, 6))

> from(#(1, 2))
> |> tuple6(int, float, string, int, int, int)
Error([
  DecodeError(expected: "6 element tuple", found: "2 element tuple", path: []),
])
pub fn unsafe_coerce(a: Dynamic) -> a

Unsafely casts a Dynamic value into any other type.

This is an escape hatch for the type system that may be useful when wrapping native Erlang APIs. It is to be used as a last measure only!

If you can avoid using this function, do!