Skip to content

Instantly share code, notes, and snippets.

@ndemengel
Created May 11, 2012 10:26
Show Gist options
  • Save ndemengel/2658827 to your computer and use it in GitHub Desktop.
Save ndemengel/2658827 to your computer and use it in GitHub Desktop.
Towards Pattern Matching in Java - See comment #4 at http://kerflyn.wordpress.com/2012/05/09/towards-pattern-matching-in-java/
package snippet;
import static snippet.Snippet.ClassPattern.inCaseOf;
import static snippet.Snippet.IntegerPattern.inCaseOf;
import static snippet.Snippet.OtherwisePattern.otherwise;
import static snippet.Snippet.StringPattern.inCaseOf;
import com.google.common.base.Function;
public class Snippet {
public static interface Pattern<R> {
boolean matches(Object value);
R apply(Object value);
}
public static class PatternMatching<R> {
private final Pattern<R>[] patterns;
public PatternMatching(final Pattern<R>... patterns) {
this.patterns = patterns;
}
public R matchFor(final Object value) {
for (Pattern<R> pattern : patterns) {
if (pattern.matches(value)) {
return pattern.apply(value);
}
}
throw new IllegalArgumentException("cannot match " + value);
}
}
public static class ClassPattern<T, R> implements Pattern<R> {
private final Class<T> clazz;
private final Function<T, R> function;
public ClassPattern(final Class<T> clazz, final Function<T, R> function) {
this.clazz = clazz;
this.function = function;
}
public boolean matches(final Object value) {
return clazz.isInstance(value);
}
@SuppressWarnings("unchecked")
public R apply(final Object value) {
return function.apply((T) value);
}
public static <T, R> Pattern<R> inCaseOf(final Class<T> clazz, final Function<T, R> function) {
return new ClassPattern<T, R>(clazz, function);
}
}
public static class StringPattern<R> implements Pattern<R> {
private final String pattern;
private final Function<String, R> function;
public StringPattern(final String pattern, final Function<String, R> function) {
this.pattern = pattern;
this.function = function;
}
public boolean matches(final Object value) {
return pattern.equals(value);
}
public R apply(final Object value) {
return function.apply((String) value);
}
public static <R> Pattern<R> inCaseOf(final String pattern, final Function<String, R> function) {
return new StringPattern<R>(pattern, function);
}
}
public static class IntegerPattern<R> implements Pattern<R> {
private final Integer pattern;
private final Function<Integer, R> function;
public IntegerPattern(final int pattern, final Function<Integer, R> function) {
this.pattern = pattern;
this.function = function;
}
public boolean matches(final Object value) {
return pattern.equals(value);
}
public R apply(final Object value) {
return function.apply((Integer) value);
}
public static <R> Pattern<R> inCaseOf(final int pattern, final Function<Integer, R> function) {
return new IntegerPattern<R>(pattern, function);
}
}
public static class OtherwisePattern<R> implements Pattern<R> {
private final Function<Object, R> function;
public OtherwisePattern(final Function<Object, R> function) {
this.function = function;
}
public boolean matches(final Object value) {
return true;
}
public R apply(final Object value) {
return function.apply(value);
}
public static <R> Pattern<R> otherwise(final Function<Object, R> function) {
return new OtherwisePattern<R>(function);
}
}
@SuppressWarnings("unchecked")
public static int fact(final int n) {
return new PatternMatching<Integer>( //
inCaseOf(Integer.class, new Function<Integer, Integer>() {
public Integer apply(final Integer x) {
return 5 + x;
}
}), //
inCaseOf("", new Function<String, Integer>() {
public Integer apply(final String _) {
return 1;
}
}), //
inCaseOf(0, new Function<Integer, Integer>() {
public Integer apply(final Integer _) {
return 1;
}
}), //
otherwise(new Function<Object, Integer>() {
public Integer apply(final Object _) {
return n * fact(n - 1);
}
})).matchFor(n);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment