package fj; import fj.control.parallel.Actor; import fj.control.parallel.Promise; import fj.control.parallel.Strategy; import fj.data.Array; import fj.data.Either; import fj.data.IterableW; import fj.data.List; import fj.data.NonEmptyList; import fj.data.Option; import fj.data.Set; import fj.data.Stream; import fj.data.Tree; import fj.data.TreeZipper; import fj.data.Validation; import fj.data.Zipper; import java.util.ArrayList; import java.util.LinkedList; import java.util.PriorityQueue; import java.util.TreeSet; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.SynchronousQueue; import static fj.data.Option.some; import static fj.data.Stream.iterableStream; import static fj.data.Zipper.fromStream; /** * A transformation or function from A to B. This type can be represented * using the Java 7 closure syntax. * * @version %build.number% */ public abstract class F { /** * Transform A to B. * * @param a The A to transform. * @return The result of the transformation. */ public abstract B f(A a); /** * Function composition * * @param g A function to compose with this one. * @return The composed function such that this function is applied last. */ public final F o(final F g) { return new F() { public B f(final C c) { return F.this.f(g.f(c)); } }; } /** * First-class function composition * * @return A function that composes this function with another. */ public final F, F> o() { return new F, F>() { public F f(final F g) { return F.this.o(g); } }; } /** * Function composition flipped. * * @param g A function with which to compose this one. * @return The composed function such that this function is applied first. */ @SuppressWarnings({"unchecked"}) public final F andThen(final F g) { return g.o(this); } /** * First-class composition flipped. * * @return A function that invokes this function and then a given function on the result. */ public final F, F> andThen() { return new F, F>() { public F f(final F g) { return F.this.andThen(g); } }; } /** * Binds a given function across this function (Reader Monad). * * @param g A function that takes the return value of this function as an argument, yielding a new function. * @return A function that invokes this function on its argument and then the given function on the result. */ public final F bind(final F> g) { return new F() { @SuppressWarnings({"unchecked"}) public C f(final A a) { return g.f(F.this.f(a)).f(a); } }; } /** * First-class function binding. * * @return A function that binds another function across this function. */ public final F>, F> bind() { return new F>, F>() { public F f(final F> g) { return F.this.bind(g); } }; } /** * Function application in an environment (Applicative Functor). * * @param g A function with the same argument type as this function, yielding a function that takes the return * value of this function. * @return A new function that invokes the given function on its argument, yielding a new function that is then * applied to the result of applying this function to the argument. */ public final F apply(final F> g) { return new F() { @SuppressWarnings({"unchecked"}) public C f(final A a) { return g.f(a).f(F.this.f(a)); } }; } /** * First-class function application in an environment. * * @return A function that applies a given function within the environment of this function. */ public final F>, F> apply() { return new F>, F>() { public F f(final F> g) { return F.this.apply(g); } }; } /** * Applies this function over the arguments of another function. * * @param g The function over whose arguments to apply this function. * @return A new function that invokes this function on its arguments before invoking the given function. */ public final F> on(final F> g) { return new F>() { public F f(final A a1) { return new F() { @SuppressWarnings({"unchecked"}) public C f(final A a2) { return g.f(F.this.f(a1)).f(F.this.f(a2)); } }; } }; } /** * Applies this function over the arguments of another function. * * @return A function that applies this function over the arguments of another function. */ public final F>, F>> on() { return new F>, F>>() { public F> f(final F> g) { return F.this.on(g); } }; } /** * Promotes this function so that it returns its result in a product-1. Kleisli arrow for P1. * * @return This function promoted to return its result in a product-1. */ public final F> lazy() { return new F>() { public P1 f(final A a) { return new P1() { public B _1() { return F.this.f(a); } }; } }; } /** * Promotes this function to map over a product-1. * * @return This function promoted to map over a product-1. */ public final F, P1> mapP1() { return new F, P1>() { public P1 f(final P1 p) { return p.map(F.this); } }; } /** * Promotes this function so that it returns its result in an Option. Kleisli arrow for Option. * * @return This function promoted to return its result in an Option. */ public final F> optionK() { return new F>() { public Option f(final A a) { return some(F.this.f(a)); } }; } /** * Promotes this function to map over an optional value. * * @return This function promoted to map over an optional value. */ public final F, Option> mapOption() { return new F, Option>() { public Option f(final Option o) { return o.map(F.this); } }; } /** * Promotes this function so that it returns its result in a List. Kleisli arrow for List. * * @return This function promoted to return its result in a List. */ public final F> listK() { return new F>() { public List f(final A a) { return List.single(F.this.f(a)); } }; } /** * Promotes this function to map over a List. * * @return This function promoted to map over a List. */ public final F, List> mapList() { return new F, List>() { public List f(final List x) { return x.map(F.this); } }; } /** * Promotes this function so that it returns its result in a Stream. Kleisli arrow for Stream. * * @return This function promoted to return its result in a Stream. */ public final F> streamK() { return new F>() { public Stream f(final A a) { return Stream.single(F.this.f(a)); } }; } /** * Promotes this function to map over a Stream. * * @return This function promoted to map over a Stream. */ public final F, Stream> mapStream() { return new F, Stream>() { public Stream f(final Stream x) { return x.map(F.this); } }; } /** * Promotes this function so that it returns its result in a Array. Kleisli arrow for Array. * * @return This function promoted to return its result in a Array. */ public final F> arrayK() { return new F>() { public Array f(final A a) { return Array.single(F.this.f(a)); } }; } /** * Promotes this function to map over a Array. * * @return This function promoted to map over a Array. */ public final F, Array> mapArray() { return new F, Array>() { public Array f(final Array x) { return x.map(F.this); } }; } /** * Returns a function that comaps over a given actor. * * @return A function that comaps over a given actor. */ public final F, Actor> comapActor() { return new F, Actor>() { public Actor f(final Actor a) { return a.comap(F.this); } }; } /** * Promotes this function to a concurrent function that returns a Promise of a value. * * @param s A parallel strategy for concurrent execution. * @return A concurrent function that returns a Promise of a value. */ public final F> promiseK(final Strategy s) { return Promise.promise(s, this); } /** * Promotes this function to map over a Promise. * * @return This function promoted to map over Promises. */ public final F, Promise> mapPromise() { return new F, Promise>() { public Promise f(final Promise p) { return p.fmap(F.this); } }; } /** * Promotes this function so that it returns its result on the left side of an Either. * Kleisli arrow for the Either left projection. * * @return This function promoted to return its result on the left side of an Either. */ @SuppressWarnings({"unchecked"}) public final F> eitherLeftK() { return Either.left_().o(F.this); } /** * Promotes this function so that it returns its result on the right side of an Either. * Kleisli arrow for the Either right projection. * * @return This function promoted to return its result on the right side of an Either. */ @SuppressWarnings({"unchecked"}) public final F> eitherRightK() { return Either.right_().o(F.this); } /** * Promotes this function to map over the left side of an Either. * * @return This function promoted to map over the left side of an Either. */ @SuppressWarnings({"unchecked"}) public final F, Either> mapLeft() { return Either.leftMap_().f(F.this); } /** * Promotes this function to map over the right side of an Either. * * @return This function promoted to map over the right side of an Either. */ @SuppressWarnings({"unchecked"}) public final F, Either> mapRight() { return Either.rightMap_().f(F.this); } /** * Returns a function that returns the left side of a given Either, or this function applied to the right side. * * @return a function that returns the left side of a given Either, or this function applied to the right side. */ public final F, B> onLeft() { return new F, B>() { public B f(final Either either) { return either.left().on(F.this); } }; } /** * Returns a function that returns the right side of a given Either, or this function applied to the left side. * * @return a function that returns the right side of a given Either, or this function applied to the left side. */ public final F, B> onRight() { return new F, B>() { public B f(final Either either) { return either.right().on(F.this); } }; } /** * Promotes this function to return its value in an Iterable. * * @return This function promoted to return its value in an Iterable. */ @SuppressWarnings({"unchecked"}) public final F> iterableK() { return IterableW.arrow().f(F.this); } /** * Promotes this function to map over Iterables. * * @return This function promoted to map over Iterables. */ @SuppressWarnings({"unchecked"}) public final F, IterableW> mapIterable() { return IterableW.map().f(F.this).o(IterableW.>wrap()); } /** * Promotes this function to return its value in a NonEmptyList. * * @return This function promoted to return its value in a NonEmptyList. */ @SuppressWarnings({"unchecked"}) public final F> nelK() { return NonEmptyList.nel().o(F.this); } /** * Promotes this function to map over a NonEmptyList. * * @return This function promoted to map over a NonEmptyList. */ public final F, NonEmptyList> mapNel() { return new F, NonEmptyList>() { public NonEmptyList f(final NonEmptyList list) { return list.map(F.this); } }; } /** * Promotes this function to return its value in a Set. * * @param o An order for the set. * @return This function promoted to return its value in a Set. */ public final F> setK(final Ord o) { return new F>() { public Set f(final A a) { return Set.single(o, F.this.f(a)); } }; } /** * Promotes this function to map over a Set. * * @param o An order for the resulting set. * @return This function promoted to map over a Set. */ public final F, Set> mapSet(final Ord o) { return new F, Set>() { public Set f(final Set set) { return set.map(o, F.this); } }; } /** * Promotes this function to return its value in a Tree. * * @return This function promoted to return its value in a Tree. */ public final F> treeK() { return new F>() { public Tree f(final A a) { return Tree.leaf(F.this.f(a)); } }; } /** * Promotes this function to map over a Tree. * * @return This function promoted to map over a Tree. */ @SuppressWarnings({"unchecked"}) public final F, Tree> mapTree() { return Tree.fmap_().f(F.this); } /** * Returns a function that maps this function over a tree and folds it with the given monoid. * * @param m The monoid with which to fold the mapped tree. * @return a function that maps this function over a tree and folds it with the given monoid. */ public final F, B> foldMapTree(final Monoid m) { return Tree.foldMap_(F.this, m); } /** * Promotes this function to return its value in a TreeZipper. * * @return This function promoted to return its value in a TreeZipper. */ public final F> treeZipperK() { return treeK().andThen(TreeZipper.fromTree()); } /** * Promotes this function to map over a TreeZipper. * * @return This function promoted to map over a TreeZipper. */ public final F, TreeZipper> mapTreeZipper() { return new F, TreeZipper>() { public TreeZipper f(final TreeZipper zipper) { return zipper.map(F.this); } }; } /** * Promotes this function so that it returns its result on the failure side of a Validation. * Kleisli arrow for the Validation failure projection. * * @return This function promoted to return its result on the failure side of a Validation. */ public final F> failK() { return new F>() { public Validation f(final A a) { return Validation.fail(F.this.f(a)); } }; } /** * Promotes this function so that it returns its result on the success side of an Validation. * Kleisli arrow for the Validation success projection. * * @return This function promoted to return its result on the success side of an Validation. */ public final F> successK() { return new F>() { public Validation f(final A a) { return Validation.success(F.this.f(a)); } }; } /** * Promotes this function to map over the failure side of a Validation. * * @return This function promoted to map over the failure side of a Validation. */ public final F, Validation> mapFail() { return new F, Validation>() { public Validation f(final Validation validation) { return validation.f().map(F.this); } }; } /** * Promotes this function to map over the success side of a Validation. * * @return This function promoted to map over the success side of a Validation. */ public final F, Validation> mapSuccess() { return new F, Validation>() { public Validation f(final Validation validation) { return validation.map(F.this); } }; } /** * Returns a function that returns the failure side of a given Validation, * or this function applied to the success side. * * @return a function that returns the failure side of a given Validation, * or this function applied to the success side. */ public final F, B> onFail() { return new F, B>() { public B f(final Validation v) { return v.f().on(F.this); } }; } /** * Returns a function that returns the success side of a given Validation, * or this function applied to the failure side. * * @return a function that returns the success side of a given Validation, * or this function applied to the failure side. */ public final F, B> onSuccess() { return new F, B>() { public B f(final Validation v) { return v.on(F.this); } }; } /** * Promotes this function to return its value in a Zipper. * * @return This function promoted to return its value in a Zipper. */ public final F> zipperK() { return streamK().andThen(new F, Zipper>() { public Zipper f(final Stream stream) { return fromStream(stream).some(); } }); } /** * Promotes this function to map over a Zipper. * * @return This function promoted to map over a Zipper. */ public final F, Zipper> mapZipper() { return new F, Zipper>() { public Zipper f(final Zipper zipper) { return zipper.map(F.this); } }; } /** * Promotes this function to map over an Equal as a contravariant functor. * * @return This function promoted to map over an Equal as a contravariant functor. */ public final F, Equal> comapEqual() { return new F, Equal>() { public Equal f(final Equal equal) { return equal.comap(F.this); } }; } /** * Promotes this function to map over a Hash as a contravariant functor. * * @return This function promoted to map over a Hash as a contravariant functor. */ public final F, Hash> comapHash() { return new F, Hash>() { public Hash f(final Hash hash) { return hash.comap(F.this); } }; } /** * Promotes this function to map over a Show as a contravariant functor. * * @return This function promoted to map over a Show as a contravariant functor. */ public final F, Show> comapShow() { return new F, Show>() { public Show f(final Show s) { return s.comap(F.this); } }; } /** * Promotes this function to map over the first element of a pair. * * @return This function promoted to map over the first element of a pair. */ public final F, P2> mapFst() { return P2.map1_(F.this); } /** * Promotes this function to map over the second element of a pair. * * @return This function promoted to map over the second element of a pair. */ public final F, P2> mapSnd() { return P2.map2_(F.this); } /** * Promotes this function to map over both elements of a pair. * * @return This function promoted to map over both elements of a pair. */ public final F, P2> mapBoth() { return new F, P2>() { public P2 f(final P2 aap2) { return P2.map(F.this, aap2); } }; } /** * Maps this function over a SynchronousQueue. * * @param as A SynchronousQueue to map this function over. * @return A new SynchronousQueue with this function applied to each element. */ public final SynchronousQueue mapJ(final SynchronousQueue as) { final SynchronousQueue bs = new SynchronousQueue(); bs.addAll(iterableStream(as).map(this).toCollection()); return bs; } /** * Maps this function over a PriorityBlockingQueue. * * @param as A PriorityBlockingQueue to map this function over. * @return A new PriorityBlockingQueue with this function applied to each element. */ public final PriorityBlockingQueue mapJ(final PriorityBlockingQueue as) { return new PriorityBlockingQueue(iterableStream(as).map(this).toCollection()); } /** * Maps this function over a LinkedBlockingQueue. * * @param as A LinkedBlockingQueue to map this function over. * @return A new LinkedBlockingQueue with this function applied to each element. */ public final LinkedBlockingQueue mapJ(final LinkedBlockingQueue as) { return new LinkedBlockingQueue(iterableStream(as).map(this).toCollection()); } /** * Maps this function over a CopyOnWriteArraySet. * * @param as A CopyOnWriteArraySet to map this function over. * @return A new CopyOnWriteArraySet with this function applied to each element. */ public final CopyOnWriteArraySet mapJ(final CopyOnWriteArraySet as) { return new CopyOnWriteArraySet(iterableStream(as).map(this).toCollection()); } /** * Maps this function over a CopyOnWriteArrayList. * * @param as A CopyOnWriteArrayList to map this function over. * @return A new CopyOnWriteArrayList with this function applied to each element. */ public final CopyOnWriteArrayList mapJ(final CopyOnWriteArrayList as) { return new CopyOnWriteArrayList(iterableStream(as).map(this).toCollection()); } /** * Maps this function over a ConcurrentLinkedQueue. * * @param as A ConcurrentLinkedQueue to map this function over. * @return A new ConcurrentLinkedQueue with this function applied to each element. */ public final ConcurrentLinkedQueue mapJ(final ConcurrentLinkedQueue as) { return new ConcurrentLinkedQueue(iterableStream(as).map(this).toCollection()); } /** * Maps this function over an ArrayBlockingQueue. * * @param as An ArrayBlockingQueue to map this function over. * @return A new ArrayBlockingQueue with this function applied to each element. */ public final ArrayBlockingQueue mapJ(final ArrayBlockingQueue as) { final ArrayBlockingQueue bs = new ArrayBlockingQueue(as.size()); bs.addAll(iterableStream(as).map(this).toCollection()); return bs; } /** * Maps this function over a TreeSet. * * @param as A TreeSet to map this function over. * @return A new TreeSet with this function applied to each element. */ public final TreeSet mapJ(final TreeSet as) { return new TreeSet(iterableStream(as).map(this).toCollection()); } /** * Maps this function over a PriorityQueue. * * @param as A PriorityQueue to map this function over. * @return A new PriorityQueue with this function applied to each element. */ public final PriorityQueue mapJ(final PriorityQueue as) { return new PriorityQueue(iterableStream(as).map(this).toCollection()); } /** * Maps this function over a LinkedList. * * @param as A LinkedList to map this function over. * @return A new LinkedList with this function applied to each element. */ public final LinkedList mapJ(final LinkedList as) { return new LinkedList(iterableStream(as).map(this).toCollection()); } /** * Maps this function over an ArrayList. * * @param as An ArrayList to map this function over. * @return A new ArrayList with this function applied to each element. */ public final ArrayList mapJ(final ArrayList as) { return new ArrayList(iterableStream(as).map(this).toCollection()); } }