2023-04-05

process tree-like list structures.

part of sph-lib

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

(sph tree)

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)

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)

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))

(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

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\")

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))

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)

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

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

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

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

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

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))

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

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

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

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)))

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

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)

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

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

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))))

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

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.

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

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

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

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)

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

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

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

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

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))

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

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

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