Add a (more constrained) API for expressing filters on columns

This is to support predicate push down, which will take advantage of these constrained filter predicates.
This will need to be reconciled with the column filters currently in the `parquet.filter` package, but I wanted to get feedback on this first.

Sample usage in java:
```
// if you lie, and column "a.b.c" isn't an int column, we won't know until runtime. 
Column<Integer> abc = column("a.b.c"); 
Column<Double> xyz = column("x.y.z");

FilterPredicate predicate =
      and(not(or(eq(abc, 7), eq(abc, 17))), gtEq(xyz, 100.0));
```

Sample usage in scala:
```
val abc = Column[Int]("a.b.c")
val xyz = Column[Double]("x.y.z")
val predicate = !((abc === 7) || (abc === 17)) && (xyz >= 100.0)
```
what's the advantage of giving that control to the input Object?
Here I make a dynamic call to getClass() because I don't want an Lt to be `.equals()` to an Eq for example.

Is it so that a proxy or wrapper class can still pretend to be the thing it delegates / wraps? I see how that would solve some problems but also complicates things as well. Here I've got a pretty strict idea of equality, and it's on a private final set of classes (this would be a sealed trait in scala)