Optimize framework

How do we build backend specific optimizations on expressions?

Given some expression and some data we might want to manipulate the expression prior to entering the `compute` interpreter chain.  These manipulations/optimizations might be backend specific.  To that end I propose a new dispatched function

```Python
@dispatch(Expr, BackendData)
def optimize(expr, data):
    return new_expr
```

Immediately this has implications for bcolz and #740 

Open question - how do we do optimizations when we have a few different data resources?

This also includes a variety of small organizational fixes discovered while digging into `compute/core.py`

cc @cpcloud 
I see above that `optimize` only takes two arguments, should this be a splat operator?