fj.P2 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of functionaljava Show documentation
Show all versions of functionaljava Show documentation
Functional Java is an open source library that supports closures for the Java programming language
package fj;
import static fj.Function.*;
import static fj.data.optic.PLens.pLens;
import fj.data.*;
import fj.data.optic.Lens;
import fj.data.optic.PLens;
/**
* A product-2.
*
* @version %build.number%
*/
public abstract class P2 {
/**
* Access the first element of the product.
*
* @return The first element of the product.
*/
public abstract A _1();
/**
* Access the second element of the product.
*
* @return The second element of the product.
*/
public abstract B _2();
@Override
public final boolean equals(Object other) {
return Equal.equals0(P2.class, this, other, () -> Equal.p2Equal(Equal.anyEqual(), Equal.anyEqual()));
}
@Override
public final int hashCode() {
return Hash.p2Hash(Hash.anyHash(), Hash.anyHash()).hash(this);
}
/**
* Swaps the elements around in this product.
*
* @return A new product-2 with the elements swapped.
*/
public final P2 swap() {
return P.lazy(P2.this::_2, P2.this::_1);
}
/**
* Map the first element of the product.
*
* @param f The function to map with.
* @return A product with the given function applied.
*/
public final P2 map1(final F f) {
P2 self = this;
return P.lazy(() -> f.f(self._1()), self::_2);
}
/**
* Map the second element of the product.
*
* @param f The function to map with.
* @return A product with the given function applied.
*/
public final P2 map2(final F f) {
return P.lazy(P2.this::_1, () -> f.f(P2.this._2()));
}
/**
* Split this product between two argument functions and combine their output.
*
* @param f A function that will map the first element of this product.
* @param g A function that will map the second element of this product.
* @return A new product with the first function applied to the second element
* and the second function applied to the second element.
*/
public final P2 split(final F f, final F g) {
final F, P2> ff = map1_(f);
final F, P2> gg = map2_(g);
return compose(ff, gg).f(this);
}
/**
* Duplicates this product on the first element, and maps the given function across the duplicate (Comonad pattern).
*
* @param k A function to map over the duplicated product.
* @return A new product with the result of the given function applied to this product as the first element,
* and with the second element intact.
*/
public final P2 cobind(final F, C> k) {
P2 self = this;
return P.lazy(() -> k.f(self), self::_2);
}
/**
* Duplicates this product into the first element (Comonad pattern).
*
* @return A new product with this product in its first element and with the second element intact.
*/
public final P2, B> duplicate() {
final F, P2> id = identity();
return cobind(id);
}
/**
* Replaces the first element of this product with the given value.
*
* @param c The value with which to replace the first element of this product.
* @return A new product with the first element replaced with the given value.
*/
public final P2 inject(final C c) {
final F, C> co = constant(c);
return cobind(co);
}
/**
* Applies a list of comonadic functions to this product, returning a list of values.
*
* @param fs A list of functions to apply to this product.
* @return A list of the results of applying the given list of functions to this product.
*/
public final List sequenceW(final List, C>> fs) {
List.Buffer cs = List.Buffer.empty();
for (final F, C> f : fs)
cs = cs.snoc(f.f(this));
return cs.toList();
}
public final List> traverseList(final F> f) {
return f.f(_2()).map(x -> P.p(_1(), x));
}
public final Stream> traverseStream(final F> f) {
return f.f(_2()).map(x -> P.p(_1(), x));
}
public final IO> traverseIO(final F> f) {
return IOFunctions.map(f.f(_2()), x -> P.p(_1(), x));
}
public final Option> traverseOption(final F> f) {
return f.f(_2()).map(x -> P.p(_1(), x));
}
public final Either> traverseEither(final F> f) {
return f.f(_2()).right().map(x -> P.p(_1(), x));
}
/**
* Applies a stream of comonadic functions to this product, returning a stream of values.
*
* @param fs A stream of functions to apply to this product.
* @return A stream of the results of applying the given stream of functions to this product.
*/
public final Stream sequenceW(final Stream, C>> fs) {
return fs.isEmpty()
? Stream.nil()
: Stream.cons(fs.head().f(this), () -> sequenceW(fs.tail()._1()));
}
/**
* Returns the 1-product projection over the first element.
*
* @return the 1-product projection over the first element.
*/
public final P1 _1_() {
return F1Functions.lazy(P2.__1()).f(this);
}
/**
* Returns the 1-product projection over the second element.
*
* @return the 1-product projection over the second element.
*/
public final P1 _2_() {
return F1Functions.lazy(P2.__2()).f(this);
}
/**
* Provides a memoising P2 that remembers its values.
*
* @return A P2 that calls this P2 once for any given element and remembers the value for subsequent calls.
*/
public final P2 memo() {
P2 self = this;
return new P2() {
private final P1 a = P1.memo(u -> self._1());
private final P1 b = P1.memo(u -> self._2());
public A _1() {
return a._1();
}
public B _2() {
return b._1();
}
};
}
/**
* A first-class version of the split function.
*
* @param f A function that will map the first element of the given product.
* @param g A function that will map the second element of the given product.
* @return A function that splits a given product between the two given functions and combines their output.
*/
public static F, P2> split_(final F f, final F g) {
return p -> p.split(f, g);
}
/**
* Promotes a function so that it maps the first element of a product.
*
* @param f The function to promote.
* @return The given function, promoted to map the first element of products.
*/
public static F, P2> map1_(final F f) {
return p -> p.map1(f);
}
/**
* Promotes a function so that it maps the second element of a product.
*
* @param f The function to promote.
* @return The given function, promoted to map the second element of products.
*/
public static F, P2> map2_(final F f) {
return p -> p.map2(f);
}
/**
* Sends the given input value to both argument functions and combines their output.
*
* @param f A function to receive an input value.
* @param g A function to receive an input value.
* @param b An input value to send to both functions.
* @return The product of the two functions applied to the input value.
*/
public static P2 fanout(final F f, final F g, final B b) {
return join(P.p2()).f(b).split(f, g);
}
/**
* Maps the given function across both the elements of the given product.
*
* @param f A function to map over a product.
* @param p A product over which to map.
* @return A new product with the given function applied to both elements.
*/
public static P2 map(final F f, final P2 p) {
return p.split(f, f);
}
/**
* Returns a curried form of {@link #swap()}.
*
* @return A curried form of {@link #swap()}.
*/
public static F, P2> swap_() {
return P2::swap;
}
/**
* Returns a function that returns the first element of a product.
*
* @return A function that returns the first element of a product.
*/
public static F, A> __1() {
return P2::_1;
}
/**
* Returns a function that returns the second element of a product.
*
* @return A function that returns the second element of a product.
*/
public static F, B> __2() {
return P2::_2;
}
/**
* Transforms a curried function of arity-2 to a function of a product-2
*
* @param f a curried function of arity-2 to transform into a function of a product-2
* @return The function, transformed to operate on on a product-2
*/
public static F, C> tuple(final F> f) {
return p -> f.f(p._1()).f(p._2());
}
/**
* Transforms an uncurried function of arity-2 to a function of a product-2
*
* @param f an uncurried function of arity-2 to transform into a function of a product-2
* @return The function, transformed to operate on on a product-2
*/
public static F, C> tuple(final F2 f) {
return tuple(curry(f));
}
/**
* Transforms a function of a product-2 to an uncurried function or arity-2.
*
* @param f A function of a product-2 to transform into an uncurried function.
* @return The function, transformed to an uncurried function of arity-2.
*/
public static F2 untuple(final F, C> f) {
return (a, b) -> f.f(P.p(a, b));
}
@Override
public final String toString() {
return Show.p2Show(Show.anyShow(), Show.anyShow()).showS(this);
}
/**
* Optic factory methods for a P2
*/
public static final class Optic {
private Optic() {
throw new UnsupportedOperationException();
}
/**
* Polyomorphic lens targeted on _1.
*/
public static PLens, P2, A, C> _1p() {
return pLens(__1(), a -> p2 -> P.p(a, p2._2()));
}
/**
* Monomorphic lens targeted on _1.
*/
public static Lens, A> _1() {
return new Lens<>(_1p());
}
/**
* Polyomorphic lens targeted on _2.
*/
public static PLens, P2, B, C> _2p() {
return pLens(__2(), b -> p2 -> P.p(p2._1(), b));
}
/**
* Monomorphic lens targeted on _1.
*/
public static Lens, B> _2() {
return new Lens<>(_2p());
}
}
}