fj.data.fingertrees.FingerTree 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.data.fingertrees;
import fj.*;
import fj.data.Option;
import fj.data.Seq;
import fj.data.Stream;
import static fj.Monoid.intAdditionMonoid;
import static fj.Monoid.intMaxMonoid;
import static fj.data.Stream.nil;
/**
* Provides 2-3 finger trees, a functional representation of persistent sequences supporting access to the ends in
* amortized O(1) time. Concatenation and splitting time is O(log n) in the size of the smaller piece.
* A general purpose data structure that can serve as a sequence, priority queue, search tree, priority search queue
* and more.
*
* This class serves as a datastructure construction kit, rather than a datastructure in its own right. By supplying
* a monoid, a measurement function, insertion, deletion, and so forth, any purely functional datastructure can be
* emulated. See {@link Seq} for an example.
*
* Based on "Finger trees: a simple general-purpose data structure", by Ralf Hinze and Ross Paterson.
*
* @param The monoidal type with which to annotate nodes.
* @param The type of the tree's elements.
*/
public abstract class FingerTree {
private final Measured m;
/**
* Folds the tree to the right with the given function and the given initial element.
*
* @param f A function with which to fold the tree.
* @param z An initial element to apply to the fold.
* @return A reduction of this tree by applying the given function, associating to the right.
*/
public abstract B foldRight(final F> f, final B z);
public final B foldRight(final F2 f, final B z) {
return foldRight(F2Functions.curry(f), z);
}
/**
* Folds the tree to the right with the given function.
*
* @param f A function with which to fold the tree.
* @return A reduction of this tree by applying the given function, associating to the right.
*/
public abstract A reduceRight(final F> f);
/**
* Folds the tree to the left with the given function and the given initial element.
*
* @param f A function with which to fold the tree.
* @param z An initial element to apply to the fold.
* @return A reduction of this tree by applying the given function, associating to the left.
*/
public abstract B foldLeft(final F> f, final B z);
public final B foldLeft(final F2 f, final B z) {
return foldLeft(F2Functions.curry(f), z);
}
/**
* Folds the tree to the left with the given function.
*
* @param f A function with which to fold the tree.
* @return A reduction of this tree by applying the given function, associating to the right.
*/
public abstract A reduceLeft(final F> f);
/**
* Maps the given function across this tree, measuring with the given Measured instance.
*
* @param f A function to map across the values of this tree.
* @param m A measuring with which to annotate the tree.
* @return A new tree with the same structure as this tree, with each element transformed by the given function,
* and nodes annotated according to the given measuring.
*/
public abstract FingerTree map(final F f, final Measured m);
public final FingerTree filter(final F f) {
FingerTree tree = new Empty<>(m);
return foldLeft((acc, a) -> f.f(a) ? acc.snoc(a) : acc, tree);
}
/**
* Returns the sum of this tree's annotations.
*
* @return the sum of this tree's annotations.
*/
public abstract V measure();
/**
* Indicates whether this tree is empty.
*
* @return true if this tree is the empty tree, otherwise false.
*/
public final boolean isEmpty() {
return this instanceof Empty;
}
public final Measured measured() {
return m;
}
/**
* Provides pattern matching on trees. This is the Church encoding of the FingerTree datatype.
*
* @param empty The function to apply to this empty tree.
* @param single A function to apply if this tree contains a single element.
* @param deep A function to apply if this tree contains more than one element.
* @return The result of the function that matches this tree structurally, applied to this tree.
*/
public abstract B match(final F, B> empty, final F, B> single,
final F, B> deep);
FingerTree(final Measured m) {
this.m = m;
}
/**
* Constructs a Measured instance for the element type, given a monoid and a measuring function.
*
* @param monoid A monoid for the measures.
* @param measure A function with which to measure element values.
* @return A Measured instance for the given element type, that uses the given monoid and measuring function.
*/
public static Measured measured(final Monoid monoid, final F measure) {
return Measured.measured(monoid, measure);
}
/**
* Returns a builder of trees and tree components that annotates them using the given Measured instance.
*
* @param m A Measured instance with which to annotate trees, digits, and nodes.
* @return A builder of trees and tree components that annotates them using the given Measured instance.
*/
public static MakeTree mkTree(final Measured m) {
return new MakeTree<>(m);
}
/**
* Adds the given element to this tree as the first element.
*
* @param a The element to add to the front of this tree.
* @return A new tree with the given element at the front.
*/
public abstract FingerTree cons(final A a);
/**
* Adds the given element to this tree as the last element.
*
* @param a The element to add to the end of this tree.
* @return A new tree with the given element at the end.
*/
public abstract FingerTree snoc(final A a);
/**
* The first element of this tree. This is an O(1) operation.
*
* @return The first element if this tree is nonempty, otherwise throws an error.
*/
public abstract A head();
public final Option headOption() {
return isEmpty() ? Option.none() : Option.some(head());
}
/**
* Performs a reduction on this finger tree using the given arguments.
*
* @param nil The value to return if this finger tree is empty.
* @param cons The function to apply to the head and tail of this finger tree if it is not empty.
* @return A reduction on this finger tree.
*/
public final B uncons(B nil, F2, B> cons) {
return isEmpty() ? nil : cons.f(head(), tail());
}
/**
* The last element of this tree. This is an O(1) operation.
*
* @return The last element if this tree is nonempty, otherwise throws an error.
*/
public abstract A last();
/**
* The tree without the first element. This is an O(1) operation.
*
* @return The tree without the first element if this tree is nonempty, otherwise throws an error.
*/
public abstract FingerTree tail();
/**
* The tree without the last element. This is an O(1) operation.
*
* @return The tree without the last element if this tree is nonempty, otherwise throws an error.
*/
public abstract FingerTree init();
/**
* Appends one finger tree to another.
*
* @param t A finger tree to append to this one.
* @return A new finger tree which is a concatenation of this tree and the given tree.
*/
public abstract FingerTree append(final FingerTree t);
/**
* Splits this tree into a pair of subtrees at the point where the given predicate, based on the measure,
* changes from false
to true
. This is a O(log(n)) operation.
*
* @return Pair: the subtree containing elements before the point where pred
first holds and the subtree
* containing element at and after the point where pred
first holds. Empty if pred
never holds.
*/
public final P2, FingerTree> split(final F predicate) {
if (!isEmpty() && predicate.f(measure())) {
final P3, A, FingerTree> lxr = split1(predicate);
return P.p(lxr._1(), lxr._3().cons(lxr._2()));
} else {
return P.p(this, mkTree(m).empty());
}
}
/**
* Like split
, but returns the element where pred
first holds separately.
*
* Throws an error if the tree is empty.
*/
public final P3, A, FingerTree> split1(final F predicate) {
return split1(predicate, measured().zero());
}
abstract P3, A, FingerTree> split1(final F predicate, final V acc);
public abstract P2 lookup(final F o, final int i);
public abstract int length();
public static FingerTree emptyIntAddition() {
return empty(intAdditionMonoid, Function.constant(1));
}
/**
* Creates an empty finger tree with elements of type A and node annotations
* of type V.
*
* @param m A monoid to combine node annotations
* @param f Function to convert node element to annotation.
* @return An empty finger tree.
*/
public static FingerTree empty(Monoid m, F f) {
return FingerTree.mkTree(measured(m, f)).empty();
}
/**
* Returns a finger tree which combines the integer node annotations with the
* maximum function. A priority queue with integer priorities.
*/
public static FingerTree> emptyIntMax() {
return empty(intMaxMonoid, (P2 p) -> p._1());
}
public abstract Stream toStream();
}