2023-04-05

(sph tree)

process tree-like list structures.

part of sph-lib

library description

denoted

  a representation using pairs where the first element denotes the nesting level and the second element is content

  (a b (c (d e)) f)-> ((0 . a) (1 . b) (2 . c) (3 . d) (3 . e) (0 . 4))

prefix-tree

  first elements of lists interpreted as parent of tail elements. similar to scheme code for procedure application

  (a b (c (d e)) f)

  example with nesting marked by indent

    a

      b

      c

        d

          e

      f

module name

(sph tree)

exported bindings

procedure: denoted-tree->prefix-tree a [depth-start] ->
list [integer] -> list
convert a tree representation like this ((0 a) (1 b) (2 c) (1 d)) to this (a (b c) d).
cases like ((0 a) (3 b) (0 c)) are converted to (a ((b)) c)
procedure: denoted-tree->tree a [depth-start] ->
list:((integer any ...) ...) [integer] -> list
convert a tree representation like this ((0 a) (1 b) (2 c) (1 d)) to this (a (b (c) d))
syntax: denoted-tree->tree-inner a depth-start r-2 r update-r ...
procedure: denoted-tree-adjust-depth a operator arguments ... ->
procedure list integer -> list
map the nesting-depth of each element with operator and arguments.
the lowest possible depth is bounded to zero.
example:
(denoted-tree-adjust-depth a + 1)
procedure: denoted-tree-minimise-depth a ->
procedure list integer -> list
decrease nesting-depth for all element until at least one element has a nesting-depth of zero
procedure: prefix-tree->denoted-tree a initial-depth ... ->
list [integer] -> list
like tree ->
denoted-tree but the nesting-depth number corresponds to prefix-tree interpretation. example
(a b (c (d e)) f) -> ((0 . a) (1 . b) (2 . c) (3 . d) (3 . e) (0 . 4))
procedure: prefix-tree->infix-tree a [prefix->infix] ->
list [procedure:{any -> any}] -> list
converts list structures like (or a b (and c d)) to (a or b or (c and d))
the optional procedure translates prefixes
procedure: prefix-tree->paths a ->
list -> (string ...)
regard tree as a nested list representation of a filesystem file and directory structure
and return a flat list of filesystem path strings.
example:
(prefix-tree->paths (list \"/usr\" (list \"bin\" (list \"share\" \"guile\") \"include\") \"/var\"))
creates
(list
\"/usr/bin\"
\"/usr/share/guile\"
\"/usr/include\"
\"/var\")
procedure: prefix-tree->relations a ->
list -> (pair ...)
create a list of all individual relations between prefix and tail elements or tail element prefixes.
example:
((a (b c (d e)))) -> ((a . b) (b . c) (b . d) (d . e))
procedure: prefix-tree-context-match a pattern ->
list list -> boolean
true if pattern exists in prefix-tree with the same tree interpretation as prefix-tree-context-produce.
example: (a b (d c)) contains patterns (a d c) and (a b) and (a d)
procedure: prefix-tree-map f a ->
{any:prefix list:tail} list -> list
map only lists, split into prefix and tail
procedure: prefix-tree-map-c f continue& a ->
procedure:{prefix tail} procedure:{list procedure:f procedure:continue:{list ->}} list -> list
maps over only the lists, split into prefix and tail.
the procedure continue& gets a procedure argument that when called continues the iteration. if it is not called,
the iteration stops and the result of continue& is the main result
procedure: prefix-tree-map-c-depth f continue a [inc depth-init] ->
{any:prefix list:tail any} {list procedure:f {list ->} any}:continue list [{integer -> integer}] -> list
like prefix-tree-map-c but with additional arguments for the current nesting-depth
procedure: prefix-tree-map-depth f a [initial-depth] ->
{any:prefix list:tail integer:depth -> any} list [integer] -> list
like prefix-tree-map but with an additional argument for the current nesting-depth
procedure: prefix-tree-map-depth-flat proc a initial-depth ... ->
{integer any -> any} list [integer] -> (any ...)
like tree ->
denoted-tree-->flat but the nesting-depth number corresponds to prefix-tree interpretation
procedure: prefix-tree-map-with-context f a ->
{any list:upper-prefixes} list -> list
like (prefix-tree-map) but with an additional argument for parent prefixes
procedure: prefix-tree-produce f a ->
{any ... -> any} list:prefix-tree -> list
calls f for each combination of prefix and tail
procedure: prefix-tree-produce-with-context f a [ignore-prefixes] ->
{element context -> any} list -> list
context is a list containing nested-list prefixes in bottom-to-top order.
for example (a (d e f) k (g h i) j) leads to f called with each of the following arguments:
(d (a)), (e (d a)), (f (d a)),(k (a)), (g (a)), (h (g a)), (i (g a)), (j (a))
ignore-prefixes ignores lists that are themselves prefixes
procedure: prefix-tree-produce-with-context-mm f a ->
procedure:{any list -> any} list -> list
like prefix-tree-produce-with-context but lists can be used as list prefixes for many-to-many relations
procedure: prefix-tree-product a [ignore-prefixes?] ->
procedure: prefix-tree-product-mm a ->
procedure: prefix-tree-replace-prefix a replacements ->
list ((to-replace . replacement) ...) -> list
replace all list prefixes, the first element of a list, in tree based on the given replacements structure
variable: sph-tree-description
procedure: tree->denoted-tree a initial-depth ... ->
list [integer] -> list
convert a tree to an association list where each element is a list having a nesting-depth number
as the first element. similar to this is the usage of indentation for nesting depth.
(a b (c (d e)) f) -> ((0 . a) (0 . b) (1 . c) (2 . d) (2 . e) (0 . f))
procedure: tree-any f a ->
procedure list -> false/any
call f with each tree element list or leaf from top to bottom and return the first true result of f.
can be used to extract single elements from tree. aliased as tree-any and tree-extract
procedure: tree-contains-all? a equal? search-values ... ->
list {any any -> boolean} any ... -> boolean
like tree-contains? but true only if every of the search-values has been found
procedure: tree-contains-some-not? a equal? search-values ... ->
list {any any -> boolean} any ... -> boolean
like tree-contains? but true only if any of the search-values is not contained
procedure: tree-contains-some? a equal? search-values ... ->
list {any any -> boolean} any ... -> boolean
like tree-contains? and true if any of the search-values is found
procedure: tree-contains? a search-value [equal?] ->
list any [procedure:{any any -> boolean}] -> boolean
compares all list and non-list elements with search-value and returns true on a match
procedure: tree-each f a ->
procedure:{any ->} list ->
call f for every element in tree, lists and non-lists.
list elements left to right, nested lists bottom to top.
tree-for-each
procedure: tree-each-leaf f a ->
procedure:{any ->} list ->
call f for each non-list element in tree
procedure: tree-every f a ->
procedure: tree-extract f a ->
procedure list -> false/any
call f with each tree element list or leaf from top to bottom and return the first true result of f.
can be used to extract single elements from tree. aliased as tree-any and tree-extract
procedure: tree-filter predicate a ->
procedure:{element -> any/boolean} list -> list
call predicate for each non-list and list element in tree and
only keep the elements for which predicate returned true.
elements left to right, nested lists bottom to top.
example
(tree-filter (l (a) (or (list? a) (even? a))) (q (1 2 3 (4 5 (6 7) (8 9 10)))))
->
(2 (4 (6) (8 10)))
procedure: tree-filter-flat predicate a ->
procedure:{any -> boolean/any} list -> list
results in a flat list of all list and non-lists elements of tree
for which predicate returned true
procedure: tree-filter-leafs predicate a ->
like tree-filter but calls predicate only for non-list elements
procedure: tree-filter-lists predicate a ->
like tree-filter but calls predicate only for list elements.
example - keep only lists with more than 3 elements
(tree-filter-lists (l (a) (< 3 (length a))) (q (1 2 3 (4 5 (6 7) (8 9 10)))))
->
(1 2 3)
procedure: tree-find predicate a ->
procedure:{element -> any/boolean} list -> any
find a sub-tree that contains an element that matches predicate
procedure: tree-finder find f a ->
procedure:{predicate list ... -> any} procedure:{element -> any/boolean} list -> any
call f with each tree list and leaf from top to bottom and return true results of f
procedure: tree-fold p r t ->
procedure:{any:element any:result -> any:result} any:result list:tree -> any
fold over all lists and non-list elements in tree
elements from left to right, nested lists bottom to top.
lists passed to f will be fold results from list elements that have already been processed.
see tree-fold-right for examples
procedure: tree-fold-depth p r t [n inc] ->
procedure:{element result integer:depth} any tree [integer:depth procedure:{integer -> integer}] -> any
like tree-fold but keeps track of the current nesting depth
procedure: tree-fold-right p r t ->
procedure:{any:element any:result -> any:result} any:result list:tree -> any:result
fold over all list and non-list elements in tree.
elements from left to right, nested lists bottom to top
example 1
(tree-fold-right
(l (a r) (pair a r))
(list)
(q (1 2 3 (4 5 (6 7) (8 9 10)))))
->
(q (1 2 3 (4 5 (6 7) (8 9 10))))
example 2
(tree-fold-right
(l (a r) (if (list? a) a (if (even? a) (pair a r) r)))
(list) (q (1 2 3 (4 5 (6 7) (8 9 10)))))
->
(q (1 2 3 (4 5 (6 7) (8 9 10))))
procedure: tree-fold-right-depth f r t [depth inc] ->
procedure:{any:element any:result -> any:result} any:result list:tree -> any
fold over all list and non-list elements in tree.
elements from left to right, nested lists bottom to top
procedure: tree-map f a ->
procedure:{any -> any} list -> list
maps elements left to right and nested lists bottom to top.
not map the topmost tree structure itself.
procedure: tree-map-depth f a [initial-depth] ->
procedure:{any:element integer:depth} list [integer] -> list
like tree-map but also passes a number for the current nesting depth to f
procedure: tree-map-depth-flat f a initial-depth ... ->
procedure:{integer:depth any:element -> any:result-element} list [integer] -> (any ...)
map elements of tree to a flat list. apply f with a number
stating how deeply the element is nested in other lists and the current element
procedure: tree-map-leafs f a ->
procedure:{any -> any} list -> list
call f only with non-list elements, all other elements are kept
procedure: tree-map-lists f a ->
{list -> any} list -> list
like tree-map but pass only the lists in tree to f, skipping and keeping non-list elements. bottom-to-top
procedure: tree-map-lists-depth f a [depth-init map-depth] ->
{list integer:depth -> any} list [integer {integer -> integer:next-depth}] -> list
like tree-map-lists with additional arguments for the current nesting depth
procedure: tree-map-lists-self f a ->
{list -> any} list -> list
like tree-map-and-self but calls f only for list elements
procedure: tree-map-self f a ->
{any -> any} list -> list
like tree-map-lists but also map the given list itself
procedure: tree-map-with-state f a init ... ->
{any any:custom-state-value ... -> list:custom-state-values} -> (list:mapped-elements any:custom-state-value ...)
like tree-map but can carry and update a number of custom values per call, similar to fold-multiple
procedure: tree-mapper map f a ->
procedure:{procedure list ... -> list} procedure:{element -> new-element} list -> list
map over lists and sub-lists using the given map procedure, which needs to have the same
signature as \"map\".
maps from bottom to top
procedure: tree-mapper-produce map f a b ->
procedure:{f list:elements -> any} procedure:{any:element-a any:element-b -> any}:f list list -> any
call f with each ordered combination between elements of two lists with a
map procedure that is called nested like
(each (lambda (a) (each (lambda (b) (f a b)) b)) a)
procedure: tree-mapper-top map f a ->
procedure:{procedure list ... -> list} procedure:{element -> new-element} list -> list
maps from top to bottom.
list results of f will be entered for further mapping.
this procedure is used to map sub-lists before eventually
mapping their elements if the map result is a list
procedure: tree-produce f a b ->
procedure:{any any -> any} list list -> any
apply f with every possible ordered combination of list and non-list elements of trees.
traverses like tree-map
procedure: tree-produce-lists f a b ->
like tree-produce only for list elements
procedure: tree-produce-lists-depth f a b [inc depth-init] ->
{any:element-a any:element-b integer:depth-a integer:depth-b} list:list-a list:list-b [{integer -> integer} integer] -> list
procedure: tree-replace-at-once predicate f a ->
procedure:{element -> boolean} procedure:{list:matched-elements -> list} list -> list
searches through tree recursively, collecting all elements (including lists) that match collect-proc, then calls
f with a list of matched elements. the result of f must of length zero (no replacement) or matched-element-count (replaces all matches).
results in the tree with the matched elements are replaced in order by the result elements from calling f
procedure: tree-replace-by-list a replace? replacements ->
list {any -> boolean} (any ...) -> list
replace each non-list element in tree that matches replace? with the next element from replacements.
it is an error if there are more replacements than matches
procedure: tree-splice predicate a ->
prodecure:{element -> boolean/any} list -> list
merge nested lists with that match predicate with their parent list.
example
(tree-splice (l (a) (= 3 (length a))) (q (1 2 3 (4 5 (6 7) (8 9 10)))))
->
(1 2 3 (4 5 (6 7) 8 9 10))
procedure: tree-transform a descend ascend terminal ->
list procedure procedure procedure -> any
descend :: any:element procedure:recurse-descend -> (any:result-element boolean:continue?)
ascend :: any:element -> any:result-element
terminal :: any:element -> any:result-element
map/transform list and sub-lists first top to bottom, calling \"descend\" for each sub-list,
then bottom to top, calling \"ascend\" for lists and \"terminal\" for non-lists/leafs.
descend should return a list of two values: the first for the result and the second a boolean indicating if the result
should be passed to ascend and terminal (true) or if that should be skipped (false).
example use cases:
* compile s-expression list trees into string output languages by mapping all expressions and sub-expressions to strings
* replace some lists in a tree
procedure: tree-transform* a descend ascend terminal states ... ->
list procedure procedure procedure any ... -> any
descend :: any:element procedure:recurse-descend any:state ... -> (any:result-element boolean:continue? any:state ...)
ascend :: any:element any:state ... -> (any:result-element any:state ...)
terminal :: any:element any:state ... -> (any:result-element any:state ...)
like tree-transform but also takes, passes and updates caller specified values
procedure: tree-transform-ascend rest leaf-list recurse-descend ascend terminal states ->
procedure: tree-transform-descend-identity a ... ->
any ... -> (#f #t)
a tree-transform descend procedure that does not do anything