-
Notifications
You must be signed in to change notification settings - Fork 136
X For comprehensions
For comprehensions are a handy short cut for combining nested flatMap operations. For example we can sequence nested calls to methods that return a type that supports flatMap such as Option, Try, Stream, IO and flatten out the result to a single Option, Try, Stream or IO.
E.g. imagine a car parking system that attaches a monthly membership fee to each user (depending on selected grade) and potential costs per use to each of the users registered cars (again depending on grade). A typical business class may have methods something like this
public Option<User> load(long id);
public Option<List<Car>> extractCarDetails(User user);
public Option<BigDecimal> totalBalance(User user,List<Car> cars);
Chaining calls together to calculate a users total outstanding balance would involve messy nested flatMaps.
Option<BigDecimal> balance = load(100L).flatMap(user->extractCarDetails(user)
.flatMap(cars->totalBalance(user,cars));
This can be rewritten, in a cleaner form using for comprehensions
Option<BigDecimal> balance = load(100L).forEach2(this::extractCarDetails,this::totalBalance);
Most types in cyclops X with a flatMap method will offer forEach2/3/4 methods directly on the type, as syntax sugar for nested flatMap operations. Types that support this form of Operation include
- Monad Types in cyclops.control (Eval, Future, Either, Ior, Try, Option, Maybe, LazyEither/3/4/5, Trampoline)
- Persistent collections (cyclops.data)
- Types that implemented IterableX
- ReactiveSeq
the forEach methods accept Functions of increasing arity (Function, BiFunction, Function3, Function4) that expose each of the current values on the stack.
An alternative mechanism is provided on some classes via an internal inner class called Comprehensions. The Comprehensions inner class consists of a larger number of overloaded forEach methods. Each method accepts a Function with a Tuple of increasing arity. In some cases this may be cleaner to use than the direct forEach methods - particularly where all available values are not needed in each subsequent computation, or where the methods being called accept Tuples as input parameters.
Types in the core of Cyclops that support the Comprehensions inner class approach are
- IO
- Managed
- Unrestricted
- Option
- Maybe
- Eval
- Unrestricted
Types in Cyclops pure that support the Comprehensions inner class approach are
- Identity
- Free
- Active
- Nested
The example using Option above rewritten using the inner class approach looks like this
Option<BigDecimal> balance = Comprehensions.forEach(load(100L),
this::extractCarDetails,
t2->totalBalance(t2._1(),t2._2());
oops - my bad