Returns the grouped list of all subtrees of a node. If
Node is a leaf node (cf. is_leaf/1), this
is the empty list, otherwise the result is always a nonempty list,
containing the lists of subtrees of Node, in
left-to-right order as they occur in the printed program text, and
grouped by category. Often, each group contains only a single
subtree.
Depending on the type of Node, the size of some
groups may be variable (e.g., the group consisting of all the
elements of a tuple), while others always contain the same number
of elements - usually exactly one (e.g., the group containing the
argument expression of a case-expression). Note, however, that the
exact structure of the returned list (for a given node type) should
in general not be depended upon, since it might be subject to
change without notice.
The function subtrees/1 and the constructor functions
make_tree/2 and update_tree/2 can be a
great help if one wants to traverse a syntax tree, visiting all its
subtrees, but treat nodes of the tree in a uniform way in most or all
cases. Using these functions makes this simple, and also assures that
your code is not overly sensitive to extensions of the syntax tree
data type, because any node types not explicitly handled by your code
can be left to a default case.
For example:
postorder(F, Tree) ->
F(case subtrees(Tree) of
[] -> Tree;
List -> update_tree(Tree,
[[postorder(F, Subtree)
|| Subtree <- Group]
|| Group <- List])
end).
maps the function F on Tree and all its
subtrees, doing a post-order traversal of the syntax tree. (Note
the use of update_tree/2 to preserve annotations.) For
a simple function like:
f(Node) ->
case type(Node) of
atom -> atom("a_" ++ atom_name(Node));
_ -> Node
end.
the call postorder(fun f/1, Tree) will yield a new
representation of Tree in which all atom names have
been extended with the prefix "a_", but nothing else (including
annotations) has been changed.
See also: is_leaf/1, make_tree/2, update_tree/2.