Skip to content

Instantly share code, notes, and snippets.

@tomwhoiscontrary
Last active October 29, 2017 21:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomwhoiscontrary/e41d52e9c98a706552be66f8a5f2fc17 to your computer and use it in GitHub Desktop.
Save tomwhoiscontrary/e41d52e9c98a706552be66f8a5f2fc17 to your computer and use it in GitHub Desktop.
An attempt at translating Clojure transducers into Java to confuse and annoy
import java.io.IOException;
import java.util.function.BiFunction;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Transducers {
public static void main(String[] args) throws IOException {
// Java doesn't have these as builtins, as far as i know
Function<Integer, Integer> inc = i -> i + 1;
Predicate<Integer> odd = i -> i % 2 != 0;
// (def inc-and-filter (comp (map inc) (filter odd?)))
Transducer<Integer, Integer> incAndFilter = comp(map(inc), filter(odd));
// (def special+ (inc-and-filter +))
Reducer<Integer, Integer> specialPlus = incAndFilter.reducingWith(Integer::sum);
// (special+ 1 1)
// ;; 1
// (special+ 1 2)
// ;; 4
System.out.println(specialPlus.apply(1, 1));
System.out.println(specialPlus.apply(1, 2));
// (reduce special+ 0 (range 10))
// ;; 25
System.out.println(specialPlus.reduce(0, IntStream.range(0, 10).boxed()));
}
// I Put on My Robe and Rich Hickey Wig ...
interface Transducer<T, U> extends Function<Consumer<T>, Consumer<U>> {
default <A> Reducer<A, U> reducingWith(Reducer<A, T> reducer) {
return (a, u) -> {
class Reduction implements Consumer<T> {
private A accumulator = a;
@Override
public void accept(T value) {
accumulator = reducer.apply(accumulator, value);
}
}
Reduction reduction = new Reduction();
apply(reduction).accept(u);
return reduction.accumulator;
};
}
}
// a little helper interface, because Java is not naturally good at reduction
interface Reducer<A, T> extends BiFunction<A, T, A> {
default A reduce(A init, Stream<T> values) {
return values.reduce(init, this, throwingCombiner());
}
}
// this is only relevant for a parallel reduce, which i don't want to get into here!
private static <A> BinaryOperator<A> throwingCombiner() {
return (a, b) -> {
throw new UnsupportedOperationException();
};
}
public static <T> Transducer<T, T> filter(Predicate<T> predicate) {
return c -> t -> {
if (predicate.test(t)) c.accept(t);
};
}
public static <T, U> Transducer<T, U> map(Function<U, T> function) {
return c -> t -> {
c.accept(function.apply(t));
};
}
public static <T, U, V> Transducer<T, V> comp(Transducer<U, V> first, Transducer<T, U> second) {
return c -> first.apply(second.apply(c));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment