All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jnape.palatable.lambda.traversable.LambdaIterable Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
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 as) {
        this.as = (Iterable) as;
    }

    /**
     * Unwrap the underlying {@link Iterable}.
     *
     * @return the wrapped Iterable
     */
    public Iterable unwrap() {
        return as;
    }

    @Override
    public  LambdaIterable fmap(Function 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> f) { return wrap(flatten(map(a -> f.apply(a).>coerce().unwrap(), as))); } @Override public Applicative, App> traverse( Function> fn, Function, ? extends Applicative, 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 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()); } }