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;
/**
* 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 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 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 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;
}
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();
/**
* 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);
}