fj.data.fingertrees.Digit 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.vector.V2;
import fj.data.vector.V3;
import fj.data.vector.V4;
import static fj.data.fingertrees.FingerTree.mkTree;
/**
* A digit is a vector of 1-4 elements. Serves as a pointer to the prefix or suffix of a finger tree.
*/
public abstract class Digit {
/**
* Folds this digit to the right using the given function and the given initial value.
*
* @param f A function with which to fold this digit.
* @param z An initial value to apply at the rightmost end of the fold.
* @return The right reduction of this digit with the given function and the given initial value.
*/
public abstract B foldRight(final F> f, final B z);
/**
* Folds this digit to the left using the given function and the given initial value.
*
* @param f A function with which to fold this digit.
* @param z An initial value to apply at the leftmost end of the fold.
* @return The left reduction of this digit with the given function and the given initial value.
*/
public abstract B foldLeft(final F> f, final B z);
/**
* Folds this digit to the right using the given function.
*
* @param f A function with which to fold this digit.
* @return The right reduction of this digit with the given function.
*/
public final A reduceRight(final F> f) {
return match(new F, A>() {
public A f(final One one) {
return one.value();
}
}, new F, A>() {
public A f(final Two two) {
final V2 v = two.values();
return f.f(v._1()).f(v._2());
}
}, new F, A>() {
public A f(final Three three) {
final V3 v = three.values();
return f.f(v._1()).f(f.f(v._2()).f(v._3()));
}
}, new F, A>() {
public A f(final Four four) {
final V4 v = four.values();
return f.f(v._1()).f(f.f(v._2()).f(f.f(v._3()).f(v._4())));
}
});
}
/**
* Folds this digit to the right using the given function.
*
* @param f A function with which to fold this digit.
* @return The right reduction of this digit with the given function.
*/
public final A reduceLeft(final F> f) {
return match(new F, A>() {
public A f(final One one) {
return one.value();
}
}, new F, A>() {
public A f(final Two two) {
final V2 v = two.values();
return f.f(v._1()).f(v._2());
}
}, new F, A>() {
public A f(final Three three) {
final V3 v = three.values();
return f.f(f.f(v._1()).f(v._2())).f(v._3());
}
}, new F, A>() {
public A f(final Four four) {
final V4 v = four.values();
return f.f(f.f(f.f(v._1()).f(v._2())).f(v._3())).f(v._4());
}
});
}
/**
* Maps a function across the elements of this digit, measuring with the given measurement.
*
* @param f A function to map across the elements of this digit.
* @param m A measuring for the function's domain (destination type).
* @return A new digit with the same structure as this digit, but with all elements transformed
* with the given function and measured with the given measuring.
*/
public final Digit map(final F f, final Measured m) {
return match(new F, Digit>() {
public Digit f(final One one) {
return new One(m, f.f(one.value()));
}
}, new F, Digit>() {
public Digit f(final Two two) {
return new Two(m, two.values().map(f));
}
}, new F, Digit>() {
public Digit f(final Three three) {
return new Three(m, three.values().map(f));
}
}, new F, Digit>() {
public Digit f(final Four four) {
return new Four(m, four.values().map(f));
}
});
}
/**
* Structural pattern matching on digits. Applies the function that matches the structure of this digit.
*
* @param one A function to apply to this digit if it's One.
* @param two A function to apply to this digit if it's Two.
* @param three A function to apply to this digit if it's Three.
* @param four A function to apply to this digit if it's Four.
* @return The result of applying the function matching this Digit.
*/
public abstract B match(final F, B> one, final F, B> two, final F, B> three,
final F, B> four);
private final Measured m;
Digit(final Measured m) {
this.m = m;
}
final Measured measured() { return m; }
/**
* Returns the sum of the measurements of this digit according to the monoid.
*
* @return the sum of the measurements of this digit according to the monoid.
*/
public final V measure() {
return foldLeft(Function.curry(new F2() {
public V f(final V v, final A a) {
return m.sum(v, m.measure(a));
}
}), m.zero());
}
/**
* Returns the tree representation of this digit.
* @return the tree representation of this digit.
*/
public final FingerTree toTree() {
final MakeTree mk = mkTree(m);
return match(new F, FingerTree>() {
public FingerTree f(final One one) {
return mk.single(one.value());
}
}, new F, FingerTree>() {
public FingerTree f(final Two two) {
return mk.deep(mk.one(two.values()._1()), new Empty>(m.nodeMeasured()), mk.one(two.values()._2()));
}
}, new F, FingerTree>() {
public FingerTree f(final Three three) {
return mk.deep(mk.two(three.values()._1(), three.values()._2()), new Empty>(m.nodeMeasured()),
mk.one(three.values()._3()));
}
}, new F, FingerTree>() {
public FingerTree f(final Four four) {
return mk.deep(mk.two(four.values()._1(), four.values()._2()), new Empty>(m.nodeMeasured()),
mk.two(four.values()._3(), four.values()._4()));
}
});
}
Option> tail() {
return match(
one -> Option.> none(),
two -> Option.> some(mkTree(m).one(two.values()._2())),
three -> Option.> some(mkTree(m).two(three.values()._2(), three.values()._3())),
four -> Option.> some(mkTree(m).three(four.values()._2(), four.values()._3(), four.values()._4()))
);
}
Option> init() {
return match(
one -> Option.> none(),
two -> Option.> some(mkTree(m).one(two.values()._1())),
three -> Option.> some(mkTree(m).two(three.values()._1(), three.values()._2())),
four -> Option.> some(mkTree(m).three(four.values()._1(), four.values()._2(), four.values()._3()))
);
}
abstract P3