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.Stream;
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(
One::value,
two -> {
final V2 v = two.values();
return f.f(v._1()).f(v._2());
},
three -> {
final V3 v = three.values();
return f.f(v._1()).f(f.f(v._2()).f(v._3()));
},
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(
One::value,
two -> {
final V2 v = two.values();
return f.f(v._1()).f(v._2());
},
three -> {
final V3 v = three.values();
return f.f(f.f(v._1()).f(v._2())).f(v._3());
},
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(
one -> new One<>(m, f.f(one.value())),
two -> new Two<>(m, two.values().map(f)),
three -> new Three<>(m, three.values().map(f)),
four -> 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((v, a) -> 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(
one -> mk.single(one.value()),
two -> mk.deep(mk.one(two.values()._1()), new Empty<>(m.nodeMeasured()), mk.one(two.values()._2())),
three -> mk.deep(mk.two(three.values()._1(), three.values()._2()), new Empty<>(m.nodeMeasured()), mk.one(three.values()._3())),
four -> mk.deep(mk.two(four.values()._1(), four.values()._2()), new Empty<>(m.nodeMeasured()), mk.two(four.values()._3(), four.values()._4()))
);
}
final 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()))
);
}
final 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