aol / cyclops

An advanced, but easy to use, platform for writing functional applications in Java 8.
Apache License 2.0
1.32k stars 136 forks source link

Simplify pattern matching in 2.0.0 #422

Closed johnmcclean closed 6 years ago

johnmcclean commented 7 years ago

Moving to cyclops-react 2.x is a good opportunity to simplify pattern matching based on what works (and remove what doesn't).

What works well

The 'catamorphism' type visit methods are simple, easy to use and are used extensively internally inside the library. They are also a large part of the value prop of cyclops-sum-types.

What works less well

The nested function match methods are harder to use.

We can match on the structure of most objects types by converting them to a Tuple or Either / Xor type. jOOλ Tuples have a 'map' method that could be used as the basis of a simpler pattern matching.

e.g.

Tuple2<String,Integer> structure;
structure.map( (name,age)-> result);

We can can pass a BiFunction that accepts the component values and returns a result, this function should be composed with another function that accepts two Predicates and returns the result if those predicates match.

e.g.

structure.map(match(s->s.length()>0,age->30,(name,age)->"over 30", t->"not over 30"));

with cyclops Predicates this could be rewritten as

structure.map(match(stringLengthGreaterThan(0),greaterThan(30),(name,age)->"over 30", t->"not over 30"));

If match looks something like this

match(Predicate<T1> p1, Predicate<T2> p2,BiFunction<T1,T2,R> matches, Function<Tuple<T1,T2>,R> miss) {
     return (t1,t2)-> {
           p1.test(t1) && p2.test(t1) ? matches.apply(t1,t2) : miss.apply(Tuple.tuple2(t1,t2))      

     }
}

Then we can define cases recursively inside the miss function

structure.map(match(stringLengthGreaterThan(0),greaterThan(30),(name,age)->"over 30",
                t->t.map(match(any(),greaterThan(18)),(name,age->"18 to 30",
                t->"under 18")));

We can further simplify this by defining a MTuple set of classes with a single method "match"

structure.match(stringLengthGreaterThan(0),greaterThan(30),(name,age)->"over 30",
                t->t.match(any(),greaterThan(18)),(name,age)->"18 to 30",
                t->"under 18"));

That way we can do pattern matching which just relies on plain old Java 8 Predicates with no internal infrastructure to maintain.

johnmcclean commented 7 years ago

match could well be a method on the Function type F[0-8]. That way it could be used with Tuples from most major libraries (e.g. jool via map( ) or JavaSlang via transform( )

johnmcclean commented 6 years ago

Upgraded pattern matching in Cyclops X