**Remember to review the last two lectures that you skipped!**

A method for combining data values satisfies the *closure property* if the result of the combination can itself be combined using the same method.

Closure is powerful because it permits us to create hierarchical structures. Hierarchical structures are made up of parts, which themselves are made up of parts, and so on.

For example, lists can contain lists, which can contain lists, and so on.

Several built-in functions take iterable arguments and aggregate them into a value.

```
# Return sum of an iterable of numbers, plus value of start (zero by default). If iterable is empty, return start.
sum(iterable[, start])
# Return the largest item, after applying func (identity by default).
max(iterable[, key=func])
# Return the largest iterable, after applying func (identity by default).
max(i1, i2, i3, ...[, key=func])
# Return True if bool(x) is True for all values x in the iterable. If iterable is empty, return True.
all(iterable)
# Return True if bool(x) is True for any values x in the iterable. If iterable is empty, return True.
any(iterable)
```

People often refer to labels by their locations: "each parent is the sum of its children."

A **tree** has a **root label** and a list of **branches**, where each **branch** is a **tree**. A **tree** starts at the **root**, and a **tree** with zero **branches** is called a **leaf**.

Each location in a tree is called a **node**, and each **node** has a **label** that can be any value. One node can be the **parent/child** of another, and the top node is the **root node**.

A **path** is a sequence of **nodes**, typically from a **root** to a **leaf**. Each such path is unique.

```
>>> tree(3, [tree(1),
... tree(2, [tree(1),
... tree(1)])])
[3, [1], [2, [1], [1]]]
```

```
def tree(label, branches=[]):
for branch in branches:
assert is_tree(branch)
return [label] + list(branches)
def label(tree):
return tree[0]
def branches(tree):
return tree[1:]
def is_tree(tree):
if type(tree) != list or len(tree) < 1:
return False
for branch in branches(tree):
if not is_tree(branch):
return False
return True
def is_leaf(tree):
return not branches(tree)
```

The `draw(list)`

function on code.cs61a.org allows us to visualize any list, no matter how deep. Using the code written above, `draw(list)`

will display a tree -- rather than boxed lists, it will display tree "leaves." The `autodraw()`

function will draw any list or tree created.

Recursion!

```
def count_leaves(t):
if is_leaf(t):
return 1
else:
return sum([count_leaves(b) for b in branches(t)])
```