Skip to content

Instantly share code, notes, and snippets.

@apskii
Created November 13, 2013 17:51
Show Gist options
  • Save apskii/7453335 to your computer and use it in GitHub Desktop.
Save apskii/7453335 to your computer and use it in GitHub Desktop.
package apsk.jpatmat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
public class Entry {
// Simple Arithmetic Language
static abstract class Term {
// Hybrid Matcher
public <R> R match(
Function<Lit, R> f1,
Function<Sum, R> f2,
Function<Mul, R> f3
) {
if (this instanceof Lit)
return f1.apply((Lit) this);
else if (this instanceof Sum)
return f2.apply((Sum) this);
else if (this instanceof Mul)
return f3.apply((Mul) this);
return null;
}
}
static abstract class PairTerm extends Term {
public final Term fst;
public final Term snd;
public PairTerm(Term fst, Term snd) {
this.fst = fst;
this.snd = snd;
}
}
static class Sum extends PairTerm {
public Sum(Term fst, Term snd) { super(fst, snd); }
@Override public String toString() {
return "(" + fst.toString() + " + " + snd.toString() + ")";
}
}
static class Mul extends PairTerm {
public Mul(Term fst, Term snd) { super(fst, snd); }
@Override public String toString() {
return "(" + fst.toString() + " * " + snd.toString() + ")";
}
}
static class Lit extends Term {
public final int val;
public Lit(int val) {
this.val = val;
}
@Override public String toString() {
return String.valueOf(val);
}
}
// Generic Lambda Pattern-Matcher
static <I, R,
T1 extends I,
T2 extends I,
T3 extends I
>
R match(I x,
Class<T1> c1, Function<T1, R> f1,
Class<T2> c2, Function<T2, R> f2,
Class<T3> c3, Function<T3, R> f3
) {
Class<?> c = x.getClass();
if (c.isAssignableFrom(c1))
return f1.apply((T1) x);
else if (c.isAssignableFrom(c2))
return f2.apply((T2) x);
else if (c.isAssignableFrom(c3))
return f3.apply((T3) x);
return null;
}
// Eval with Generic Matcher
static int eval(Term term) {
return match(term,
Lit.class, lit -> lit.val,
Sum.class, sum -> eval(sum.fst) + eval(sum.snd),
Mul.class, mul -> eval(mul.fst) * eval(mul.snd)
);
}
// Eval with Static Matcher
static int evalInstanceof(Term term) {
if (term instanceof Lit)
return ((Lit) term).val;
else if (term instanceof Sum)
return evalInstanceof(((Sum) term).fst) + evalInstanceof(((Sum) term).snd);
else if (term instanceof Mul)
return evalInstanceof(((Mul) term).fst) * evalInstanceof(((Mul) term).snd);
return -111;
}
// Eval with Hybrid Matcher
static int evalSM(Term term) {
return term.match(
lit -> lit.val,
sum -> evalSM(sum.fst) + evalSM(sum.snd),
mul -> evalSM(mul.fst) * evalSM(mul.snd)
);
}
// Generate randomized terms
static List<Term> mkTerms(int count) {
Random rndGen = new Random();
ArrayList<Term> terms = new ArrayList<>(count);
for (int i = 0; i < count; ++i)
terms.add(
new Sum(
new Lit(1),
new Mul(
new Lit(rndGen.nextInt(20)),
new Sum(
new Lit(3), new Lit(4)
)
)
)
);
return terms;
}
// Turn function to an action, performed specified number of times
static <I,R> Consumer<I> times(int count, Function<I,R> f) {
return x -> {
for (int i = 0; i < count; ++i) f.apply(x);
};
}
public static void main(String[] args) {
List<Term> terms = mkTerms(1000000);
System.out.println("1,000,000 terms initialized...");
for (int n = 1; n < 1000; n *= 10) {
System.out.println("[ " + n + " evals ]:");
long startMillis = System.currentTimeMillis();
terms.forEach(times(n, Entry::eval));
System.out.println("Generic: " + (System.currentTimeMillis() - startMillis));
startMillis = System.currentTimeMillis();
terms.forEach(times(n, Entry::evalInstanceof));
System.out.println("Static: " + (System.currentTimeMillis() - startMillis));
startMillis = System.currentTimeMillis();
terms.forEach(times(n, Entry::evalSM));
System.out.println("Hybrid: " + (System.currentTimeMillis() - startMillis));
System.out.println();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment