-
Notifications
You must be signed in to change notification settings - Fork 51
For Comprehensions Explained
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.

For comprehensions are useful for iterating over nested structures (e.g. collections, Streams, Optionals, CompletableFutures or other Monads).
Given a list of Strings
List<String> list = Arrays.asList("hello","world","3");
We can iterate over them using Java 5 'foreach' syntax
for(String element : list){
System.out.println(element);
}
The equivalent for comprehension would be
Do.add(list)
.yield( element -> element )
.forEach(System.out::println);
We have simply converted the list to a Stream and are using Stream forEach to iterate over it.
But.. if we nest our looping
List<Integer> numbers = Arrays.asList(1,2,3,4);
for(String element : list){
for(Integer num : numbers){
System.out.println(element + num);
}
}
Things start to become a little unwieldy, but a little less so with for comprehensions
Do.add(list)
.with(element -> numbers)
.yield( element -> num -> element + num )
.forEach(System.out::println);
Let's add a third level of nesting
List<Date> dates = Arrays.asList(new Date(),new Date(0));
for(String element : list){
for(Integer num : numbers){
for(Date date : dates){
System.out.println(element + num + ":" + date);
}
}
}
And the for comprehension looks like
Do.add(list)
.add(numbers)
.add(dates)
.yield( element -> num -> date -> element + num+":"+date )
.forEach(System.out::println);
Stream map
list.stream()
.map(element -> element.toUpperCase())
.collect(Collectors.toList());
Can be written as
ForComprehensions.foreach1(c -> c.mapAs$1(list))
.yield( (Vars1<String> v) -> c.$1().toUpperCase())
.collect(Collectors.toList());
Running a for comprehension over a list (stream) and an Optional
List<String> strs = Arrays.asList("hello","world");
Optional<String> opt = Optional.of("cool");
Do.add(strs)
.add(opt)
.yield(v1->v2 -> v1 + v2)
.forEach(System.out::println);
Outputs : [hellocool, worldcool]
Or the other way around
List<String> strs strs = Arrays.asList("hello","world");
Optional<String> opt = Optional.of("cool");
Do.add(opt)
.add(strs)
.yield(v1->v2 -> v1+ v2)
.<String>toSequence()
.forEach(System.out::println);
assertThat(results.get(),hasItem("coolhello"));
assertThat(results.get(),hasItem("coolworld"));
Outputs : coolhello],[coolworld
The first type used controls the interaction!
CompletableFuture defined first
Stream defined first
Guards (filter commands) can be placed at any stage of a for comprehension. E.g.
Stream<Double> s = Do.with(Arrays.asList(10.00,5.00,100.30))
.and((Double d)->Arrays.asList(2.0))
.filter((Double d)-> (Double e) -> e*d>10.00)
.yield((Double base)->(Double bonus)-> base*(1.0+bonus));
double total = s.collect(Collectors.summingDouble(t->t));
assertThat(total,equalTo(330.9));