
fj.data.fingertrees.FingerTree Maven / Gradle / Ivy
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();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy