Streams à la carte
Extensible Pipelines with Object Algebras
Aggelos Biboudis¹, Nick Palladinos², George Fourtounis¹, Yannis Smaragdakis¹
University of Athens¹
Nessos Information Technologies²
(under review)
Iterator<Long> iterator = Stream
.of(v)
.flatMap(x -> Stream.iterate(0L, i -> i + 2).map(y -> x * y))
.iterator();
iterator.hasNext(); // Out-of-memory :-(
interface ExpFactory {
Exp lit(int x);
Exp add(Exp e1, Exp e2);
}
interface ExpFactory<Exp> {
Exp lit(int x);
Exp add(Exp e1, Exp e2);
}
<Exp> Exp mkAnExp(ExpFactory<Exp> f) {
return f.add(f.lit(1),
f.add(f.lit(2), f.lit(3)));
}
interface StreamAlg<C<_>> {
<T> C<T> source(T[] array);
<T, R> C<R> map(Function<T, R> f, C<T> s);
<T, R> C<R> flatMap(Function<T, C<R>> f, C<T> s);
<T> C<T> filter(Predicate<T> f, C<T> s);
}
(for intermediate operators)
interface ExecStreamAlg<E<_>, C<_>> extends StreamAlg<C> {
<T> E<Long> count(C<T> s);
<T> E<T> reduce(T identity, BinaryOperator<T> acc, C<T> s);
}
(for terminal operators)
Add new operators (by extending the algebra)
interface TakeStreamAlg<C<_>> extends StreamAlg<C> {
<T> C<T> take(int n, C<T> s);
}
Add new behavior (by implementing the algebra)
class PushFactory implements StreamAlg<Push>
PushFactory alg = new PushFactory();
int sum = alg.sum(
alg.map(x -> x * x,
alg.filter(x -> x % 2 == 0,
alg.source(v)))).value;
<E, C> E<Long> cart(ExecStreamAlg<E, C> alg) {
return alg.reduce(0L, Long::sum,
alg.flatMap(x ->
alg.map(y -> x * y, alg.source(v2)),
alg.source(v1)));
}
Declaring streams: reducing a Cartesian product
cart(new ExecPushFactory()).value;
cart(new ExecPullFactory()).value;
cart(new ExecFusedPullFactory()).value;
cart(new LogFactory<>(new ExecPushFactory())).value;
cart(new LogFactory<>(new ExecPushFactory())).value;
cart(new ExecFutureFactory<>(new ExecPushFactory())).get();
cart(new ExecFutureFactory<>(new ExecPullFactory())).get();
Using streams with various factories
public class Id<T> implements App<Id.t, T> {
public final T value;
public Id(T value) {
this.value = value;
}
public static <A> Id<A> prj(App<Id.t, A> app) {
return (Id<A>) app;
}
public static <A> App<Id.t, A> inj(Id<A> app) {
return (App<Id.t, A>) app;
}
public static class t {}
}
interface App<C, T> {}
The deck: http://slides.com/biboudis/streamalg-presentation
The code (will appear): http://github.com/biboudis/streamalg