Skip to content

Pattern Matching Explained

johnmcclean-aol edited this page Feb 24, 2016 · 3 revisions

Cyclops has merged with simple-react. Please update your bookmarks (stars :) ) to https://github.com/aol/cyclops-react

All new develpoment on cyclops occurs in cyclops-react. Older modules are still available in maven central.

screen shot 2016-02-22 at 8 44 42 pm

Pattern Matching is like a Java switch statement on steroids. Cyclops Pattern Matching, at a very low level is built on a simple combination of a Predicate (which determines the match) and Function (which determines the action on match). Cyclops then provides layers of builders on top of this to make complex matching statements succinct and simple.

Testing a value or type

Possibly the most common use case for pattern matching is to match on a particular value of an Object, or to match on it's type. When the argument matches the supplied type or value, we trigger the associated action for that case.

Match by type

 new MyCase(4,5,6).matchType(c ->c.isType((MyCase ce) -> "hello")

 @Value
  static class MyCase  implements Matchable{
	int a;
	int b;
	int c;
}

when

Match by value

  Matching.when().isValue(1).thenApply(v->"found 1")
          .match(1).orElse("not found");

when value

Testing the composite values of a collection or class

Another common use case is to test all or some of the values in a collection or the fields of a class. The Matchable interface provides two methods to do this match : which simply matches the values, and _match which also allows Type checking on the Collection / Class supplying the values.

Match values

  new MyCase(1,2,3).match(this::cases);
  private <I,T> CheckValues<Object, T> cases(CheckValues<I, T> c) {
	return c.with(1,2,3).then(i->"hello")
		.with(4,5,6).then(i->"goodbye");
}

Wildcards such as Predicates.__ can also be used e.g.

   private <I,T> CheckValues<Object, T> cases(CheckValues<I, T> c) {
	return c.with(__,2,3).then(i->"hello")
		.with(4,5,__).then(i->"goodbye");
}

whenvalues

Match values recursively

It is possible to also pattern match against the fields or values in a Class / Collection recursively nested in the Object under test.

Predicates.with( ) can be used to further break down and match any Object.

e.g.

   Matching.<Expression>whenValues().isType( (Add<Const,Mult> a)-> new Const(1))
								.with(__,type(Mult.class).with(__,new Const(0)))
			.whenValues().isType( (Add<Mult,Const> a)-> new Const(0)).with(type(Mult.class).with(__,new Const(0)),__)
			.whenValues().isType( (Add<Add,Const> a)-> new Const(-100)).with(with(__,new Const(2)),__)
			
			
			.apply(e).orElse(new Const(-1));


@AllArgsConstructor(access=AccessLevel.PRIVATE) static abstract class  Expression implements Decomposable{}
final static class X extends Expression{ }
@Value final static class Const extends Expression  { int value; }
@Value final static class Add<T extends Expression, R extends Expression> extends Expression { T left; R right; }
@Value final static class Mult<T extends Expression, R extends Expression> extends Expression  { T left; R right; }
@Value final static class Neg<T extends Expression> extends Expression { T expr; }

As shown above Predicates.type can be used to Type check rather than value check a field - and as all predicates supplied are JDK predicates - it is possible to extend the framework with your own.

whenvalues recursive

Clone this wiki locally