Refactor recursion out of compute 

Previously we wrote lots of `compute` methods like the following:

```Python
@dispatch(Projection, DataFrame)
def compute(t, df):
    parent = compute(t.parent, df)
    return parent[list(t.columns)]
```

The traversal down the tree was baked into each method.  We extract this bit into an explicit `bottom_up` function and instead write methods like the following:

```Python
@dispatch(Projection, DataFrame)
def compute_one(t, df):
    return df[list(t.columns)]
```
@mwiebe might have thoughts on this.  Should the small compute functions have knowledge of non-local scope as would be necessary in the following

    accounts['name'][accounts['amount'] < 0]
    (because accounts['name'] isn't a subexpression of accounts['amount'] < 0)


I'm not pushing hard for inclusion of this PR btw.  I think it does generally simplify things, but it didn't turn out to be as essential as I anticipated.