Standard library - container

Module:

module container
  // Lookup
  def safeGet : word -> data -> data          // since PR#379
  def descend : array(word) -> data -> data   // since PR#379

  // Update
  def pathUpdate : array(word) -> data -> data -> data.          // since PR#769
  def pathUpdateAndAugment : array(word) -> data -> data -> data // since PR1804

  // Iterating
  def deepIterPath : (data -> array(word) -> null) -> data -> null  // since PR#478

  // Mapping
  def shallowMap : (data -> data) -> data -> data
  def deepMap : (data -> data) -> data -> data      // since PR#379

  // Searching
  def shallowFind : (data -> bool) -> data -> data    // since PR#379
  def deepFind : (data -> bool) -> data -> data       // since PR#379
  def shallowFindMapped : (data -> S) -> data -> S    // since PR#379
  def deepFindMapped : (data -> S) -> data -> S       // since PR#379
  def shallowFindIndex : (data -> bool) -> data -> word      // since PR#379
  def deepFindPath : (data -> bool) -> data -> array(word)   // since PR#379

  // Merging
  def shallowMerge : data -> data -> data             // since PR#769
  def deepMerge : data -> data -> data                // since PR#769
  def deepMergeBuilder : data -> data -> data                 // since PR#1700
  def mergeReplaceBuilder: data -> data -> data               // since PR#1675

  // Conversion
  def toStream : data -> data*
  def toStreamPairs : data -> [data,data]*
module end

The container module contains functions that operate on both arrays and maps.

Lookup

  def safeGet : word -> data -> data          // since PR#379
  def descend : array(word) -> data -> data   // since PR#379

safeGet(key,c) looks up a string-valued key in a map c or a number-valued key in an array c. If there is any problem doing the lookup, the value undefined will be returned (i.e. when c is neither a map nor an array, or when key or c are undefined, or when key does not fit to c, or when the container does not contain the key).

descend(path,c) walks the path in c and returns the final element. The path is an array of numbers and strings. For a number, it is expected that the remaining container is an array, and for a string it is expected that the remaining container is a map. On any problem walking the path, the value undefined is returned.

Example:

def c = { a: [1, 2, { b: "a", d: "X" } ], { b: { c: [ 3, "4" ] } } }
def v1 = descend(["a", 2, "d"], c)    // returns "X"
def v2 = descend(["b"], c)            // returns { c: [ 3, "4" ] }
def v3 = descend([], c)               // returns c
def v4 = descend(["a", 3, "b"], c)    // returns undefined
def v5 = descend(["b"], null)         // returns undefined

Update

  def pathUpdate : array(word) -> data -> data -> data.          // since PR#769
  def pathUpdateAndAugment : array(word) -> data -> data -> data // since PR1804

The function pathUpdate(path, newValue, c) descends into the container c following path and changes the value there to newValue.

Example:

def c = { a: [1, 2, { b: "a", d: "X" } ], b: { c: [ 3, "4" ] } }
def d = pathUpdate(["a", 1], "hello", c)
  // returns { a: [1, "hello", { b: "a", d: "X" } ], b: { c: [ 3, "4" ] } }

Note that there is also the built-in with notation for the case that the path is statically known:

def c = { a: [1, 2, { b: "a", d: "X" } ], b: { c: [ 3, "4" ] } }
def d = c with .a[1] = "hello"
  // returns { a: [1, "hello", { b: "a", d: "X" } ], b: { c: [ 3, "4" ] } }

The function pathUpdateAndAugment(path, newValue, c) is similar to pathUpdate. The difference is that if the path runs into a part of c where the object fields and array indices are missing, these fields/indices are added.

Example:

pathUpdateAndAugment([ "p", "y", "z" ], "hello", { p: { x: "hi" }, q: [ 99 ] })
  // returns { p: { x: "hi", y: { z: "hello" } }, q: [ 99 ] }