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)]
```
Yeah, with this refactor the above is difficult.  

See the following implementation of `compute_one`

```Python
@dispatch(Selection, (Series, DataFrame))
def compute_one(t, df):
    predicate = compute(t.predicate, {t.parent: df})
    return df[predicate]
```

In this case compute_one is only give the dataframe on which it should compute itself.  It isn't given the entire scope.  A solution would be the following

```Python
@dispatch(Selection, (Series, DataFrame), dict)
def compute_one(t, df, scope):
    predicate = compute(t.predicate, scope)
    return df[predicate]
```

I.e. we could explicitly pass down the global scope.