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
.