com.jnape.palatable.lambda.traversable.LambdaIterable Maven / Gradle / Ivy
Show all versions of lambda Show documentation
package com.jnape.palatable.lambda.traversable;
import com.jnape.palatable.lambda.functor.Applicative;
import com.jnape.palatable.lambda.monad.Monad;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.Function;
import static com.jnape.palatable.lambda.functions.builtin.fn1.Flatten.flatten;
import static com.jnape.palatable.lambda.functions.builtin.fn2.CartesianProduct.cartesianProduct;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Cons.cons;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Into.into;
import static com.jnape.palatable.lambda.functions.builtin.fn2.Map.map;
import static com.jnape.palatable.lambda.functions.builtin.fn3.FoldRight.foldRight;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;
/**
* Wrap an {@link Iterable} in a {@link Traversable} such that {@link Traversable#traverse(Function, Function)} applies
* its computation against each element of the wrapped {@link Iterable}. Returns the result of pure
if the
* wrapped {@link Iterable} is empty.
*
* @param the Iterable element type
*/
public final class LambdaIterable implements Monad, Traversable {
private final Iterable as;
@SuppressWarnings("unchecked")
private LambdaIterable(Iterable extends A> as) {
this.as = (Iterable) as;
}
/**
* Unwrap the underlying {@link Iterable}.
*
* @return the wrapped Iterable
*/
public Iterable unwrap() {
return as;
}
@Override
public LambdaIterable fmap(Function super A, ? extends B> fn) {
return wrap(map(fn, as));
}
@Override
public LambdaIterable pure(B b) {
return wrap(singleton(b));
}
/**
* {@inheritDoc}
*
* In this case, calculate the cartesian product of applications of all functions in appFn
to all
* values wrapped by this {@link LambdaIterable}.
*
* @param appFn the other applicative instance
* @param the new parameter type
* @return the zipped LambdaIterable
*/
@Override
@SuppressWarnings("Convert2MethodRef")
public LambdaIterable zip(Applicative, LambdaIterable> appFn) {
return wrap(map(into((f, x) -> f.apply(x)),
cartesianProduct(appFn.>>coerce().unwrap(), as)));
}
@Override
public LambdaIterable discardL(Applicative appB) {
return Monad.super.discardL(appB).coerce();
}
@Override
public LambdaIterable discardR(Applicative appB) {
return Monad.super.discardR(appB).coerce();
}
@Override
public LambdaIterable flatMap(Function super A, ? extends Monad> f) {
return wrap(flatten(map(a -> f.apply(a).>coerce().unwrap(), as)));
}
@Override
public Applicative, App> traverse(
Function super A, ? extends Applicative> fn,
Function super Traversable, ? extends Applicative extends Traversable, App>> pure) {
return foldRight((a, appTrav) -> appTrav.zip(fn.apply(a).fmap(b -> bs -> LambdaIterable.wrap(cons(b, bs.unwrap())))),
pure.apply(LambdaIterable.empty()).fmap(ti -> (LambdaIterable) ti),
as);
}
@Override
public boolean equals(Object other) {
if (other instanceof LambdaIterable) {
Iterator xs = as.iterator();
Iterator ys = ((LambdaIterable) other).as.iterator();
while (xs.hasNext() && ys.hasNext())
if (!Objects.equals(xs.next(), ys.next()))
return false;
return xs.hasNext() == ys.hasNext();
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(as);
}
/**
* Wrap an {@link Iterable} in a TraversableIterable
.
*
* @param as the Iterable
* @param the Iterable element type
* @return the Iterable wrapped in a TraversableIterable
*/
public static LambdaIterable wrap(Iterable extends A> as) {
return new LambdaIterable<>(as);
}
/**
* Construct an empty TraversableIterable
by wrapping {@link java.util.Collections#emptyList()}.
*
* @param the Iterable element type
* @return a TraversableIterable wrapping Collections.emptyList()
*/
public static LambdaIterable empty() {
return wrap(emptyList());
}
}