All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fj.data.fingertrees.Digit Maven / Gradle / Ivy

Go to download

Functional Java is an open source library that supports closures for the Java programming language

There is a newer version: 5.0
Show newest version
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>, A, Option>> split1(final F predicate, final V acc);

  public abstract P2 lookup(final F o, final int i);

    public abstract int length();

    public String toString() {
        return Show.digitShow(Show.anyShow(), Show.anyShow()).showS(this);
    }

    public abstract Stream toStream();


}