-
Notifications
You must be signed in to change notification settings - Fork 51
Old cyclops modules docs
Need organized.
The Decomposable Interface defines an unapply method that is used to convert the implementing Object into an iterable. This can be used to control how Cyclops performs recursive decomposition.
public <I extends Iterable<?>> I unapply();
- ValueObject
- StreamableValue
- CachedValues, PTuple1-8
As.asDecomposable(myObject).unapply().forEach(System.out::println);
com.aol.cyclops.dynamic.As provides a range of methods to dynamically convert types
- AnyM : Abstraction over any Java monad
- OptionalT : Optional Monad Transformer
- StreamT : Stream Monad Transformer
- StreamableT : Streamable Monad Transformer
- ListT : List Monad Transformer
- CompletableFutureT : CompletableFutute Monad Transformer
cyclops-monad-api is normally imported via other cyclops modules, as full functioning depends on cyclops-streams. Instructions to import it in standalone format are at the bottom of this page.
An alternative to higher-kinded types for providing a common interface over classes that define map / flatMap / filter (etc) methods or their equivalent.
Works by either using a registered 'Comprehender' that handles the actual method invocations, or by taking advantage of InvokeDynamic facility introduced in Java 7 that can make the performance of a dynamic method call almost equivalent to a static call.
Introducing the cyclops monad api
- aggregate
- applyM
- asSequence
- bind / flatMap - collection, completableFuture, optional, ReactiveSeq, stream, streamable
- empty
- filter
- map
- reduceM
- simpleFilter
Wrap a Stream inside an AnyM, and a Optional inside another, and aggregate their values
List<Integer> result = anyM(Stream.of(1,2,3,4))
.aggregate(anyM(Optional.of(5)))
.asSequence()
.toList();
assertThat(result,equalTo(Arrays.asList(1,2,3,4,5)));
- liftM : Lift a Function to a function that accepts and returns any monad type (via AnyM).
- liftM2 : Lift a BiFunction to a function that accepts and returns any monad type (via AnyM).
- sequence : Convert a collection of monads, to a single monad with a collection
- traverse : Convert a collection of Monads to a single Monad with a wrapped Collection applying the supplied function in the process
cyclops-invokedynamic cyclops-sequence-api
cyclops-streams
Fit the Stream.reduce signature. Can be used to wrap any Monoid type (e.g. functional java).
Monoid.of("",(a,b)->a+b).reduce(Stream.of("a","b","c"));
Produces "abc"
fj.Monoid m = fj.Monoid.monoid((Integer a) -> (Integer b) -> a+b,0);
Monoid<Integer> sum = As.asMonoid(m);
assertThat(sum.reduce(Stream.of(1,2,3)),equalTo(6));
Use in conjunction with Power Tuples or StreamUtils for Multiple simultanous reduction on a Stream.
The Decomposable interface specifies an unapply method (with a default implementation) that decomposes an Object into it's elemental parts. It used used in both Cyclops Pattern Matching (for recursively matching against Case classes) and Cyclops for comprehensions (where Decomposables can be lifted to Streams automatically on input - if desired).
@Test
public void test() {
assertThat(AsDecomposable.asDecomposable(new MyCase("key",10))
.unapply(),equalTo(Arrays.asList("key",10)));
}
@Value
static class MyCase { String key; int value;}
Simplify deeply nested looping (over Collections, even Streams, Optionals and more!).
- Javadoc for Cyclops For Comprehensions
- Wiki for Extensible For Comprehensions
- For comprehension examples
Two supported formats
- Type Do Notation via Do.add / with
- Untpyed Do Notation via UntypedDo.add / with
List<Integer> list= Arrays.asList(1,2,3);
List<Integer> list = Do.add(list)
.yield((Integer i)-> i +2)
.unwrap();
assertThat(Arrays.asList(3,4,5),equalTo(list));
Yield, Filter and 'and' take curried functions
(That is a chain of single input parameter functions)
Stream<Integer> stream = Do.add(asList(20,30))
.with( i->asList(1,2,3))
.yield(i-> j -> i + j+2)
.asSequence();
Parameters are stack based, the parameter to the first function is an index into the first Collection or Monad, the parameter to the second function is an index into the second Collection or Monad and so on.
The above code could be rewritten as
Stream<Integer> stream = Do.add(asList(20,30))
.with(any->asList(1,2,3))
.yield(x-> y -> x + y+2)
.asSequence();
And it would work in exactly the same way
List<Integer> list= Arrays.asList(1,2,3);
Stream<Integer> stream = Do.add(list)
.filter(a -> a>2)
.yield(a-> a +2)
.asSequence();
assertThat(Arrays.asList(5),equalTo(stream.collect(Collectors.toList())));
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 )
.unwrap()
.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 )
.unwrap()
.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)
.unwrap()
.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))
.asSequence();
double total = s.collect(Collectors.summingDouble(t->t));
assertThat(total,equalTo(330.9));
-
Collection to Stream
-
Iterable to Stream
-
Iterator to Stream
-
Array to Stream
-
Int to IntStream.range(int)
-
File to Stream
-
URL to Stream
-
BufferedReader to Stream
-
InputStream to Stream
-
ResultSet to Stream
-
Enum to Stream
-
String to Stream
-
ObjectToStreamConverter
- NullToOptionalConverter
- Optional to Optional
- Callable to CompletableFuture
- Supplier to CompletableFuture
Cyclops for comphrensions allow deeply nested iterations or monadic operations to be expressed as a simple foreach expression. The implementation is inspired by the rather excellent Groovy implementation by Mark Perry (Functional Groovy) see Groovy Null Handling Using Bind, Comprehensions and Lift. They will work with any Monad type (JDK, Functional Java, Javaslang, TotallyLazy, Cyclops etc).
The Cyclops implementation is pure Java however, and although it will revert to dynamic execution when it needs to, reflection can be avoided entirely.
- Support for custom interface definition with virtually unlimited nesting
Stream<Integer> stream = foreachX(Custom.class,
c-> c.myVar(list)
.yield(()->c.myVar()+3)
);
Optional<Integer> one = Optional.of(1);
Optional<Integer> empty = Optional.empty();
BiFunction<Integer,Integer,Integer> f2 = (a,b) -> a *b;