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

fj.F2Functions Maven / Gradle / Ivy

Go to download

Functional Java is an open source library that supports closures for the Java programming language

There is a newer version: 5.0
Show newest version
package fj;

import fj.control.parallel.Promise;
import fj.data.*;

import static fj.P.p;
import static fj.data.IterableW.wrap;
import static fj.data.Set.iterableSet;
import static fj.data.Tree.node;
import static fj.data.TreeZipper.treeZipper;
import static fj.data.Zipper.zipper;

/**
 * Created by MarkPerry on 6/04/2014.
 */
public final class F2Functions {


  private F2Functions() {
  }

  /**
     * Partial application.
     *
     * @param a The A to which to apply this function.
     * @return The function partially applied to the given argument.
     */
  public static  F f(final F2 f, final A a) {
        return b -> f.f(a, b);
    }

    /**
     * Curries this wrapped function to a wrapped function of arity-1 that returns another wrapped function.
     *
     * @return a wrapped function of arity-1 that returns another wrapped function.
     */
    public static  F> curry(final F2 f) {
        return a -> b -> f.f(a, b);
    }

    /**
     * Flips the arguments of this function.
     *
     * @return A new function with the arguments of this function flipped.
     */
    public static  F2 flip(final F2 f) {
        return (b, a) -> f.f(a, b);
    }

    /**
     * Uncurries this function to a function on tuples.
     *
     * @return A new function that calls this function with the elements of a given tuple.
     */
    public static  F, C> tuple(final F2 f) {
        return p -> f.f(p._1(), p._2());
    }

    /**
     * Promotes this function to a function on Arrays.
     *
     * @return This function promoted to transform Arrays.
     */
    public static  F2, Array, Array> arrayM(final F2 f) {
        return (a, b) -> a.bind(b, curry(f));
    }

    /**
     * Promotes this function to a function on Promises.
     *
     * @return This function promoted to transform Promises.
     */
    public static  F2, Promise, Promise> promiseM(final F2 f) {
        return (a, b) -> a.bind(b, curry(f));
    }

    /**
     * Promotes this function to a function on Iterables.
     *
     * @return This function promoted to transform Iterables.
     */
    public static  F2, Iterable, IterableW> iterableM(final F2 f) {
        return (a, b) -> IterableW.liftM2(curry(f)).f(a).f(b);
    }

    /**
     * Promotes this function to a function on Lists.
     *
     * @return This function promoted to transform Lists.
     */
    public static  F2, List, List> listM(final F2 f) {
        return (a, b) -> List.liftM2(curry(f)).f(a).f(b);
    }

    /**
     * Promotes this function to a function on non-empty lists.
     *
     * @return This function promoted to transform non-empty lists.
     */
    public static  F2, NonEmptyList, NonEmptyList> nelM(final F2 f) {
        return (as, bs) -> NonEmptyList.fromList(as.toList().bind(bs.toList(), f)).some();
    }

    /**
     * Promotes this function to a function on Options.
     *
     * @return This function promoted to transform Options.
     */
    public static  F2, Option, Option> optionM(final F2 f) {
        return (a, b) -> Option.liftM2(curry(f)).f(a).f(b);
    }

    /**
     * Promotes this function to a function on Sets.
     *
     * @param o An ordering for the result of the promoted function.
     * @return This function promoted to transform Sets.
     */
    public static  F2, Set, Set> setM(final F2 f, final Ord o) {
        return (as, bs) -> {
            Set cs = Set.empty(o);
            for (final A a : as)
                for (final B b : bs)
                    cs = cs.insert(f.f(a, b));
            return cs;
        };
    }

    /**
     * Promotes this function to a function on Streams.
     *
     * @return This function promoted to transform Streams.
     */
    public static  F2, Stream, Stream> streamM(final F2 f) {
        return (as, bs) -> as.bind(bs, f);
    }

    /**
     * Promotes this function to a function on Trees.
     *
     * @return This function promoted to transform Trees.
     */
    public static  F2, Tree, Tree> treeM(final F2 f) {
        return new F2, Tree, Tree>() {
            public Tree f(final Tree as, final Tree bs) {
                final F2, Tree, Tree> self = this;
                return node(f.f(as.root(), bs.root()), P.lazy(() -> streamM(self).f(as.subForest()._1(), bs.subForest()._1())));
            }
        };
    }

    /**
     * Promotes this function to zip two arrays, applying the function lock-step over both Arrays.
     *
     * @return A function that zips two arrays with this function.
     */
    public static  F2, Array, Array> zipArrayM(final F2 f) {
        return (as, bs) -> as.zipWith(bs, f);
    }

    /**
     * Promotes this function to zip two iterables, applying the function lock-step over both iterables.
     *
     * @return A function that zips two iterables with this function.
     */
    public static  F2, Iterable, Iterable> zipIterableM(final F2 f) {
        return (as, bs) -> wrap(as).zipWith(bs, f);
    }

    /**
     * Promotes this function to zip two lists, applying the function lock-step over both lists.
     *
     * @return A function that zips two lists with this function.
     */
    public static  F2, List, List> zipListM(final F2 f) {
        return (as, bs) -> as.zipWith(bs, f);
    }


    /**
     * Promotes this function to zip two streams, applying the function lock-step over both streams.
     *
     * @return A function that zips two streams with this function.
     */
    public static  F2, Stream, Stream> zipStreamM(final F2 f) {
        return (as, bs) -> as.zipWith(bs, f);
    }

    /**
     * Promotes this function to zip two non-empty lists, applying the function lock-step over both lists.
     *
     * @return A function that zips two non-empty lists with this function.
     */
    public static  F2, NonEmptyList, NonEmptyList> zipNelM(final F2 f) {
        return (as, bs) -> NonEmptyList.fromList(as.toList().zipWith(bs.toList(), f)).some();
    }

    /**
     * Promotes this function to zip two sets, applying the function lock-step over both sets.
     *
     * @param o An ordering for the resulting set.
     * @return A function that zips two sets with this function.
     */
    public static  F2, Set, Set> zipSetM(final F2 f, final Ord o) {
        return (as, bs) -> iterableSet(o, as.toStream().zipWith(bs.toStream(), f));
    }

    /**
     * Promotes this function to zip two trees, applying the function lock-step over both trees.
     * The structure of the resulting tree is the structural intersection of the two trees.
     *
     * @return A function that zips two trees with this function.
     */
    public static  F2, Tree, Tree> zipTreeM(final F2 f) {
        return new F2, Tree, Tree>() {
            public Tree f(final Tree ta, final Tree tb) {
                final F2, Tree, Tree> self = this;
                return node(f.f(ta.root(), tb.root()), P.lazy(() -> zipStreamM(self).f(ta.subForest()._1(), tb.subForest()._1())));
            }
        };
    }

    /**
     * Promotes this function to zip two zippers, applying the function lock-step over both zippers in both directions.
     * The structure of the resulting zipper is the structural intersection of the two zippers.
     *
     * @return A function that zips two zippers with this function.
     */
    public static  F2, Zipper, Zipper> zipZipperM(final F2 f) {
        return (ta, tb) -> {
            final F2, Stream, Stream> sf = zipStreamM(f);
            return zipper(sf.f(ta.lefts(), tb.lefts()), f.f(ta.focus(), tb.focus()), sf.f(ta.rights(), tb.rights()));
        };
    }

    /**
     * Promotes this function to zip two TreeZippers, applying the function lock-step over both zippers in all directions.
     * The structure of the resulting TreeZipper is the structural intersection of the two TreeZippers.
     *
     * @return A function that zips two TreeZippers with this function.
     */
    public static  F2, TreeZipper, TreeZipper> zipTreeZipperM(final F2 f) {
        return (ta, tb) -> {
            final F2>, Stream>, Stream>> sf = zipStreamM(treeM(f));
            final
            F2>, A, Stream>>>,
                    Stream>, B, Stream>>>,
                    Stream>, C, Stream>>>>
                    pf =
                    zipStreamM((pa, pb) -> p(zipStreamM(treeM(f)).f(pa._1(), pb._1()), f.f(pa._2(), pb._2()),
                            zipStreamM(treeM(f)).f(pa._3(), pb._3())));
            return treeZipper(treeM(f).f(ta.p()._1(), tb.p()._1()), sf.f(ta.lefts(), tb.lefts()),
                    sf.f(ta.rights(), tb.rights()), pf.f(ta.p()._4(), tb.p()._4()));
        };
    }

    public static  F2 contramapFirst(F2 target, F f) {
        return (z, b) -> target.f(f.f(z), b);
    }

    public static  F2 contramapSecond(F2 target, F f) {
        return (a, z) -> target.f(a, f.f(z));
    }

    public static  F2 contramap(F2 target, F f, F g) {
        return contramapSecond(contramapFirst(target, f), g);
    }

    public static  F2 map(F2 target, F f) {
        return (a, b) -> f.f(target.f(a, b));
    }

}