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

fj.F2 Maven / Gradle / Ivy

Go to download

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

The newest version!
package fj;

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

import java.util.function.BiFunction;

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;

/**
 * A transformation function of arity-2 from A and B to C.
 */
@FunctionalInterface
public interface F2 extends BiFunction {
  /**
   * Transform A and B to C.
   *
   * @param a The A to transform.
   * @param b The B to transform.
   * @return The result of the transformation.
   */
  C f(A a, B b);

  default C apply(A a, B b) {
    return f(a, b);
  }

  /**
   * Partial application.
   *
   * @param a The A to which to apply this function.
   * @return The function partially applied to the given argument.
   */
  default F f(final A a) {
    return b -> 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.
   */
  default F> curry() {
    return a -> b -> f(a, b);
  }

  /**
   * Flips the arguments of this function.
   *
   * @return A new function with the arguments of this function flipped.
   */
  default F2 flip() {
    return (b, a) -> 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.
   */
  default F, C> tuple() {
    return p -> f(p._1(), p._2());
  }

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

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

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

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

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

  /**
   * Promotes this function to a function on Options.
   *
   * @return This function promoted to transform Options.
   */
  default F2, Option, Option> optionM() {
    return (a, b) -> Option.liftM2(curry()).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.
   */
  default F2, Set, Set> setM(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(a, b));
      return cs;
    };
  }

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

  /**
   * Promotes this function to a function on Trees.
   *
   * @return This function promoted to transform Trees.
   */
  default F2, Tree, Tree> treeM() {
    F2 outer = this;
    return new F2, Tree, Tree>() {
      public Tree f(final Tree as, final Tree bs) {
        final F2, Tree, Tree> self = this;
        return node(outer.f(as.root(), bs.root()), P.lazy(() -> self.streamM().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.
   */
  default F2, Array, Array> zipArrayM() {
    return (as, bs) -> as.zipWith(bs, this);
  }

  /**
   * 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.
   */
  default F2, Iterable, Iterable> zipIterableM() {
    return (as, bs) -> wrap(as).zipWith(bs, this);
  }

  /**
   * 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.
   */
  default F2, List, List> zipListM() {
    return (as, bs) -> as.zipWith(bs, this);
  }


  /**
   * 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.
   */
  default F2, Stream, Stream> zipStreamM() {
    return (as, bs) -> as.zipWith(bs, this);
  }

  /**
   * 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.
   */
  default F2, NonEmptyList, NonEmptyList> zipNelM() {
    return (as, bs) -> NonEmptyList.fromList(as.toList().zipWith(bs.toList(), this)).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.
   */
  default F2, Set, Set> zipSetM(final Ord o) {
    return (as, bs) -> iterableSet(o, as.toStream().zipWith(bs.toStream(), this));
  }

  /**
   * 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.
   */
  default F2, Tree, Tree> zipTreeM() {
    F2 outer = this;
    return new F2, Tree, Tree>() {
      public Tree f(final Tree ta, final Tree tb) {
        final F2, Tree, Tree> self = this;
        return node(outer.f(ta.root(), tb.root()), P.lazy(() -> self.zipStreamM().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.
   */
  default F2, Zipper, Zipper> zipZipperM() {
    return (ta, tb) -> {
      final F2, Stream, Stream> sf = this.zipStreamM();
      return zipper(sf.f(ta.lefts(), tb.lefts()), 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.
   */
  default F2, TreeZipper, TreeZipper> zipTreeZipperM() {
    F2 outer = this;
    return (ta, tb) -> {
      final F2>, Stream>, Stream>> sf = outer.treeM().zipStreamM();
      F2>, A, Stream>>, P3>, B, Stream>>, P3>, C, Stream>>> g =
              (pa, pb) -> p(outer.treeM().zipStreamM().f(pa._1(), pb._1()), outer.f(pa._2(), pb._2()),
                      outer.treeM().zipStreamM().f(pa._3(), pb._3()));
      final
      F2>, A, Stream>>>,
              Stream>, B, Stream>>>,
              Stream>, C, Stream>>>>
              pf = g.zipStreamM();
      return treeZipper(outer.treeM().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()));
    };
  }

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

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

  default  F2 contramap(F f, F g) {
    return contramapFirst(f).contramapSecond(g);
  }

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


}