Skip to content

Creating a for comprehension builder

johnmcclean-aol edited this page Feb 24, 2016 · 4 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

Class Structure

The class structure for, for comprehensions is as follows

pattern matching structure - for comprehensions structure

com.aol.cyclops.comprehensions.ForComprehensions provides four core methods for leveraging for for comprehensions with a Scala like syntax (foreach1-4). foreachX provides an extension point that allows custom for comprehension builders to be plugged in. The cyclops Do builder is one such builder that leverages this functionality.

If you are building a library and would like to add advanced custom for comprehensions, this is probably the method to build on.

  public static <R> R foreachX(Function<ComprehensionData<?,R,? extends Initialisable>,R> fn){
	return (R)new FreeFormForComprehension().foreach((Function)fn);
}

The Do builder calls foreachX when it's yield method has been called. It's yield method passes all the information previously captured about the for comprehension at that point.

       protected <T> T yieldInternal(Function f){
		return (T)ForComprehensions.foreachX(c->build(c,f));
	}

The foreachX method above allows variables to be bound and accessed via String names

   Stream<Integer> stream = foreachX(c -> c.$("hello",list)
									.filter(()->c.<Integer>$("hello")<10)
									.yield(()-> c.<Integer>$("hello")+2));

In the above example we bind the elements of a list to the name 'hello' and then filter on the current value of that list (via the 'hello' variable), and subsequently add 2 to any remaining members - again via the 'hello' variable. It is possible to reuse this functionality externally to build very powerful for comprehension builders.

Quick custom for comprehensions

Another foreachx method directly allows custom, strongly typed for comprehensions. If you want to introduce application specific, alternative for comprehensions - this is the method to use.

 public static <X,R> R foreachX(Class<X> c,Function<X,R> fn){
	return (R)new FreeFormForComprehension(c,(Class)null).foreach(fn);
}

List<Integer> list= Arrays.asList(1,2,3);
Stream<Integer> stream = foreachX(Custom.class,  
					c-> c.myVar(list)
					     .yield(()->c.myVar()+3)
				);

  static interface Custom extends CustomForComprehension<Stream<Integer>,Custom>{
	Integer myVar();
	Custom myVar(List<Integer> value);
}
	
assertThat(Arrays.asList(4,5,6),equalTo(stream.collect(Collectors.toList())));
Clone this wiki locally