10.2.3 Generic Property Operations
These procedures work with any grove, but use only intrinsic properties.
The result of many of the following procedures is the mapping of a function on a node over a node-list, which is defined to be the node-list that results from appending in order the result of applying the function to each member of the node-list.
(node-list-property propname nl)
Returns the mapping over nl of the function on a node that returns the value that the node exhibits for the property propname or an empty node-list if the node does not exhibit a value or exhibits a null value for propname.  propname can be specified in any of the ways allowed for the node-property procedure.  It shall be an error if any node in nl exhibits a non-null, non-nodal value for propname.  This could be defined as follows:
(define (node-list-property prop nl)
  (node-list-map (lambda (snl)
                   (node-property prop snl default: (empty-node-list)))
                 nl))
(origin nl)
This is equivalent to:
(define (origin nl)
  (node-list-property 'origin nl))
(origin-to-subnode-rel snl)
Returns the value that the member of snl exhibits for the origin-to-subnode-rel-property-name property, or #f if it does not exhibit a value or exhibits a null value.  This could be defined as follows:
(define (origin-to-subnode-rel snl)
  (node-property 'origin-to-subnode-rel-property-name snl default: #f))
(tree-root nl)
This is equivalent to:
(define (tree-root nl)
  (node-list-property 'tree-root nl))
(grove-root nl)
This is equivalent to:
(define (grove-root nl)
  (node-list-property 'grove-root nl))
(children nl)
Returns the mapping over nl of the function on a node that returns the value of the node's children property, if any, and otherwise the empty node-list.  This could be defined as follows:
(define (children nl)
  (node-list-map (lambda (snl)
                   (let ((childprop (node-property 'children-property-name
                                                   snl
                                                   default: #f)))
                     (if childprop
                         (node-property childprop
                                        snl
                                        default: (empty-node-list))
                         (empty-node-list))))
                 nl))
(data nl)
Returns a string containing the concatenation of the data of each member of nl.  The data of a node is:

•  if the node has a data property, the value of its data property converted to a string, if necessary,

•  if the child has a children property, the concatenation of the data of each of the children of the node, separated by the value of the data separator property, if it has a non-null value, or

•  otherwise, an empty string.
(parent nl)
This is equivalent to:
(define (parent nl)
  (node-list-property 'parent nl))
(source nl)
This is equivalent to:
(define (source nl)
  (node-list-property 'source nl))
(subtree nl)
Returns the mapping over nl of the function on a node that returns the subtree of a node, where the subtree of a node is defined to be the node-list comprising the node followed by the subtrees of its children.  This could be defined as follows:
(define (subtree nl)
  (node-list-map (lambda (snl)
                   (node-list snl (subtree (children snl))))
                 nl))
(subgrove nl)
Returns the mapping over nl of the function on a node that returns the subgrove of a node, where the subgrove of a node is defined to be the node-list comprising the node followed by the subgroves of members of the values of each of the node's subnode properties. This could be defined as follows:
(define (subgrove nl)
  (node-list-map
   (lambda (snl)
     (node-list snl
                (subgrove
                 (apply node-list
                        (map (lambda (name)
                               (node-property name snl))
                             (node-property 'subnode-property-names
                                            snl))))))
   nl))
(descendants nl)
Returns the mapping over nl of the function on a node that returns the descendants of the node, where the descendants of a node are defined to be the result of appending the subtrees of the children of the node.  This could be defined as follows:
(define (descendants nl)
  (node-list-map (lambda (snl)
                   (subtree (children snl)))
                 nl))
(ancestors nl)
Returns the mapping over nl of the function on a node that returns the ancestors of the node, where the ancestors of a node are an empty node-list if the node is a tree root, and otherwise are the result of appending the ancestors of the parent of the node and the parent of the node.  This could be defined as follows:  
(define (ancestors nl)
  (node-list-map (lambda (snl)
                   (let loop ((cur (parent snl))
                              (result (empty-node-list)))
                     (if (node-list-empty? cur)
                         result
                         (loop (parent snl)
                               (node-list cur result)))))
                 nl))
(grove-root-path nl)
Returns the mapping over nl of the function on a node that returns the grove root path of the node, where the grove root path of a node is defined to be an empty node-list if the node is the grove root, and otherwise is the result of appending the grove root path of the origin of the node and the origin of the node. This could be defined as follows:
(define (grove-root-path nl)
  (node-list-map (lambda (snl)
                   (let loop ((cur (origin snl))
                              (result (empty-node-list)))
                     (if (node-list-empty? cur)
                         result
                         (loop (origin nl)
                               (node-list cur result)))))
                 nl))
(rsiblings nl)
Returns the mapping over nl of the function on a node that returns the reflexive siblings of the node, where the reflexive siblings of a node are defined to be the value of the origin-to-subnode relationship property of the node's origin, if the node has an origin, and otherwise the node itself. This could be defined as follows:
(define (rsiblings nl)
  (node-list-map (lambda (snl)
                   (let ((rel (origin-to-subnode-rel snl)))
                     (if rel
                         (node-property rel
                                        (origin snl)
                                        default: (empty-node-list))
                         snl)))
                 nl))
(ipreced nl)
Returns the mapping over nl of the function on a node that returns the immediately preceding sibling of the node, if any. This could be defined as follows:
(define (ipreced nl)
  (node-list-map (lambda (snl)
                   (let loop ((prev (empty-node-list))
                              (rest (siblings snl)))
                     (cond ((node-list-empty? rest)
                            (empty-node-list))
                           ((node-list=? (node-list-first rest) snl)
                            prev)
                           (else
                            (loop (node-list-first rest)
                                  (node-list-rest rest))))))
                 nl))
(ifollow nl)
Returns the mapping over nl of the function on a node that returns the immediately following sibling of the node, if any. This could be defined as follows:
(define (ifollow nl)
  (node-list-map (lambda (snl)
                   (let loop ((rest (siblings snl)))
                     (cond ((node-list-empty? rest)
                            (empty-node-list))
                           ((node-list=? (node-list-first rest) snl)
                            (node-list-first (node-list-rest rest)))
                           (else
                            (loop (node-list-rest rest))))))
                 nl))
(preced nl)
Returns the mapping over nl of the function on a node that returns the preceding siblings of the node, if any. This could be defined as follows:
(define (preced nl)
  (node-list-map (lambda (snl)
                   (let loop ((scanned (empty-node-list))
                              (rest (siblings snl)))
                     (cond ((node-list-empty? rest)
                            (empty-node-list))
                           ((node-list=? (node-list-first rest) snl)
                            scanned)
                           (else
                            (loop (node-list scanned
                                             (node-list-first rest))
                                  (node-list-rest rest))))))
                 nl))
(follow nl)
Returns the mapping over nl of the function on a node that returns the following siblings of the node, if any. This could be defined as follows:
(define (follow nl)
  (node-list-map (lambda (snl)
                   (let loop ((rest (siblings snl)))
                     (cond ((node-list-empty? rest)
                            (empty-node-list))
                           ((node-list=? (node-list-first rest) snl)
                            (node-list-rest rest))
                           (else
                            (loop (node-list-rest rest))))))
                 nl))
(grove-before? snl1 snl2)
Returns #t if snl1 is strictly before snl2 in grove order.  It is an error if snl1 and snl2 are not in the same grove.  This could be defined as follows:
(define (grove-before? snl1 snl2)
  (let ((sorted
         (node-list-intersection (subgrove (grove-root snl1))
                                 (node-list snl1 snl2))))
    (and (= (node-list-length sorted) 2)
         (node-list=? (node-list-first sorted) snl1))))
(sort-in-tree-order nl)
Returns the members of nl sorted in tree order.  Any duplicates shall be removed.  It is an error if the members of nl are not all in the same tree.  This could be defined as follows:
(define (sort-in-tree-order nl)
  (node-list-intersection (subtree (tree-root nl))
                          nl))
(tree-before? snl1 snl2)
Returns #t if snl1 is strictly before snl2 in tree order.  It is an error if snl1 and snl2 are not in the same tree.  This could be defined as follows:
(define (tree-before? snl1 snl2)
  (let ((sorted
         (sort-in-tree-order (node-list snl1 snl2))))
    (and (= (node-list-length sorted) 2)
         (node-list=? (node-list-first sorted) snl1))))
(tree-before nl)
Returns the mapping over nl of the function on a node that returns those nodes in the same tree as the node that are before the node. This could be defined as follows:
(define (tree-before nl)
  (node-list-map (lambda (snl)
                   (node-list-filter (lambda (x)
                                       (tree-before? x snl))
                                     (subtree (tree-root snl))))
                 nl))
(property-lookup propname snl if-present if-not-present)
If snl exhibits a non-null value for the property propname, property-lookup returns the result of applying if-present to that value, and otherwise returns the result of calling if-not-present without arguments.  propname can be specified in any of the ways allowed for the node-property procedure.  This could be defined as follows:
(define (property-lookup name snl if-present if-not-present)
  (let ((val (node-property name snl default: #f)))
    (cond (val (if-present val))
          ((node-property name snl default: #t) (if-not-present))
          (else (if-present val)))))
(select-by-class nl sym)
Returns a node-list comprising members of nl that have node class sym.  sym is either the application name (transformed as specified in section 10.1.5, Application Name Transformation) or the RCS name of the class.
(select-by-property nl sym proc)
Returns a node-list comprising those members of nl that have a non-nodal property named sym that exhibits a non-null value such that proc applied to it returns a true value.
(select-by-null-property nl sym)
Returns a node-list comprising members of nl for which the property sym exhibits a null value.
(select-by-missing-property nl sym)
Returns a node-list comprising members of nl for which the property sym does not exhibit a value.