Last active
October 29, 2017 21:23
-
-
Save tomwhoiscontrary/e41d52e9c98a706552be66f8a5f2fc17 to your computer and use it in GitHub Desktop.
An attempt at translating Clojure transducers into Java to confuse and annoy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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