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

fj.data.fingertrees.Deep 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.Function.constant;
import static fj.data.List.list;
import static fj.Function.flip;
import static fj.data.Stream.nil;

/**
 * A finger tree with 1-4-digits on the left and right, and a finger tree of 2-3-nodes in the middle.
 */
public final class Deep extends FingerTree {
  private final V v;
  private final Digit prefix;
  private final FingerTree> middle;
  private final Digit suffix;

  Deep(final Measured m, final V v, final Digit prefix,
       final FingerTree> middle,
       final Digit suffix) {
    super(m);
    this.v = v;
    this.prefix = prefix;
    this.middle = middle;
    this.suffix = suffix;
  }

  /**
   * Returns the first few elements of this tree.
   *
   * @return the first few elements of this tree.
   */
  public Digit prefix() {
    return prefix;
  }

  /**
   * Returns a finger tree of the inner nodes of this tree.
   *
   * @return a finger tree of the inner nodes of this tree.
   */
  public FingerTree> middle() {
    return middle;
  }

  /**
   * Returns the last few elements of this tree.
   *
   * @return the last few elements of this tree.
   */
  public Digit suffix() {
    return suffix;
  }

  @Override public  B foldRight(final F> aff, final B z) {
    return prefix.foldRight(aff, middle.foldRight(flip(Node.foldRight_(aff)), suffix.foldRight(aff, z)));
  }

  @Override public A reduceRight(final F> aff) {
    return prefix.foldRight(aff, middle.foldRight(flip(Node.foldRight_(aff)), suffix.reduceRight(aff)));
  }

  @Override public  B foldLeft(final F> bff, final B z) {
    return suffix.foldLeft(bff, middle.foldLeft(Node.foldLeft_(bff), prefix.foldLeft(bff, z)));
  }

  @Override public A reduceLeft(final F> aff) {
    return suffix.foldLeft(aff, middle.foldLeft(Node.foldLeft_(aff), prefix.reduceLeft(aff)));
  }

  @Override public  FingerTree map(final F abf, final Measured m) {
    return new Deep<>(m, v, prefix.map(abf, m), middle.map(Node.liftM(abf, m), m.nodeMeasured()),
        suffix.map(abf, m));
  }

  /**
   * Returns the sum of the measurements of this tree's elements, according to the monoid.
   *
   * @return the sum of the measurements of this tree's elements, according to the monoid.
   */
  public V measure() {
    return v;
  }

  /**
   * Pattern matching on the tree. Matches the function on the Deep tree.
   */
  @Override public  B match(final F, B> empty, final F, B> single,
                               final F, B> deep) {
    return deep.f(this);
  }

  @Override public FingerTree cons(final A a) {
    final Measured m = measured();
    final V measure = m.sum(m.measure(a), v);
    final MakeTree mk = mkTree(m);

    return prefix.match(
      one -> new Deep<>(m, measure, mk.two(a, one.value()), middle, suffix),
      two -> new Deep<>(m, measure, mk.three(a, two.values()._1(), two.values()._2()), middle, suffix),
      three -> new Deep<>(m, measure, mk.four(a, three.values()._1(), three.values()._2(), three.values()._3()), middle, suffix),
      four -> new Deep<>(m, measure, mk.two(a, four.values()._1()), middle.cons(mk.node3(four.values()._2(), four.values()._3(), four.values()._4())), suffix));
  }

  public FingerTree snoc(final A a) {
    final Measured m = measured();
    final V measure = m.sum(m.measure(a), v);
    final MakeTree mk = mkTree(m);

    return suffix.match(
      one -> new Deep<>(m, measure, prefix, middle, mk.two(one.value(), a)),
      two -> new Deep<>(m, measure, prefix, middle, mk.three(two.values()._1(), two.values()._2(), a)),
      three -> new Deep<>(m, measure, prefix, middle, mk.four(three.values()._1(), three.values()._2(), three.values()._3(), a)),
      four -> new Deep<>(m, measure, prefix, middle.snoc(mk.node3(four.values()._1(), four.values()._2(), four.values()._3())), mk.two(four.values()._4(), a)));
  }

  @Override public A head() {
    return prefix.match(
      One::value,
      two -> two.values()._1(),
      three -> three.values()._1(),
      four -> four.values()._1());
  }

  @Override public A last() {
    return suffix.match(
      One::value,
      two -> two.values()._2(),
      three -> three.values()._3(),
      four -> four.values()._4());
  }

  private static  FingerTree deepL(final Measured measured, final Option> lOpt, final FingerTree> m, final Digit r) {
    return lOpt.option(
      P.lazy(() -> m.isEmpty() ? r.toTree() : mkTree(measured).deep(m.head().toDigit(), m.tail(), r)),
      (F, FingerTree>) l -> mkTree(measured).deep(l, m, r)
    );
  }

  private static  FingerTree deepR(final Measured measured, final Option> rOpt, final FingerTree> m, final Digit l) {
    return rOpt.option(
      P.lazy(() -> m.isEmpty() ? l.toTree() : mkTree(measured).deep(l, m.init(), m.last().toDigit())),
      (F, FingerTree>) r -> mkTree(measured).deep(l, m, r)
    );
  }

  @Override public FingerTree tail() { return deepL(measured(), prefix.tail(), middle, suffix); }

  @Override public FingerTree init() { return deepR(measured(), suffix.init(), middle, prefix); }

  @Override public FingerTree append(final FingerTree t) {
    final Measured m = measured();
    return t.match(
      constant(this),
      single -> snoc(single.value()),
      deep -> new Deep<>(m, m.sum(measure(), deep.measure()), prefix,
        addDigits0(m, middle, suffix, deep.prefix, deep.middle), deep.suffix));
  }

  @Override P3, A, FingerTree> split1(final F predicate, final V acc) {
    final Measured m = measured();
    final V accL = m.sum(acc, prefix.measure());
    if (predicate.f(accL)) {
      final P3>, A, Option>> lxr = prefix.split1(predicate, acc);
      return P.p(lxr._1().option(new Empty<>(m), Digit::toTree), lxr._2(), deepL(m, lxr._3(), middle, suffix));
    } else {
      final V accM = m.sum(accL, middle.measure());
      if (predicate.f(accM)) {
        final P3>, Node, FingerTree>> mlXsMr = middle.split1(predicate, accL);
        final P3>, A, Option>> lxr = mlXsMr._2().split1(predicate, m.sum(accL, mlXsMr._1().measure()));
        return P.p(deepR(m, lxr._1(), mlXsMr._1(), prefix), lxr._2(), deepL(m, lxr._3(), mlXsMr._3(), suffix));
      } else {
        final P3>, A, Option>> lxr = suffix.split1(predicate, accM);
        return P.p(deepR(m, lxr._1(), middle, prefix), lxr._2(), lxr._3().option(new Empty<>(m), Digit::toTree));
      }
    }
  }

  @Override public P2 lookup(final F o, final int i) {
    final int spr = o.f(prefix.measure());
    if (i < spr) {
      return prefix.lookup(o, i);
    } else {
      final int spm = spr + o.f(middle.measure());
      if (i < spm) {
        final P2> p = middle.lookup(o, i - spr);
        return p._2().lookup(o, p._1());
      } else {
        return suffix.lookup(o, i - spm);
      }
    }
  }

    @Override
    public int length() {
        int midSize = middle.foldLeft((acc, n) -> acc + n.length(), 0);
        return prefix.length() + midSize + suffix.length();
    }

    private static  FingerTree> addDigits0(
            final Measured m, final FingerTree> m1,
            final Digit s1, final Digit p2,
            final FingerTree> m2) {

        final MakeTree mk = mkTree(m);
        return s1.match(
            one1 -> p2.match(
                one2 -> append1(m, m1, mk.node2(one1.value(), one2.value()), m2),
                two2 -> {
                    final V2 vs = two2.values();
                    return append1(m, m1, mk.node3(one1.value(), vs._1(), vs._2()), m2);
                },
                three -> {
                    final V3 vs = three.values();
                    return append2(m, m1, mk.node2(one1.value(), vs._1()), mk.node2(vs._2(), vs._3()), m2);
                },
                four -> {
                    final V4 vs = four.values();
                    return append2(m, m1, mk.node3(one1.value(), vs._1(), vs._2()), mk.node2(vs._3(), vs._4()), m2);
                }
            ),
            two1 -> {
                final V2 v1 = two1.values();
                return p2.match(
                    one -> append1(m, m1, mk.node3(v1._1(), v1._2(), one.value()), m2),
                    two2 -> {
                        final V2 v2 = two2.values();
                        return append2(m, m1, mk.node2(v1._1(), v1._2()), mk.node2(v2._1(), v2._2()), m2);
                    },
                    three -> {
                        final V3 v2 = three.values();
                        return append2(m, m1, mk.node3(v1._1(), v1._2(), v2._1()), mk.node2(v2._2(), v2._3()), m2);
                    },
                    four -> {
                        final V4 v2 = four.values();
                        return append2(m, m1, mk.node3(v1._1(), v1._2(), v2._1()), mk.node3(v2._2(), v2._3(), v2._4()), m2);
                    }
                );
            },
            three1 -> {
                final V3 v1 = three1.values();
                return p2.match(
                    one -> append2(m, m1, mk.node2(v1._1(), v1._2()), mk.node2(v1._3(), one.value()), m2),
                    two -> {
                        final V2 v2 = two.values();
                        return append2(m, m1, mk.node3(v1), mk.node2(v2), m2);
                    },
                    three2 -> append2(m, m1, mk.node3(v1), mk.node3(three2.values()), m2),
                    four -> append3(m, m1, mk.node3(v1),
                        mk.node2(four.values()._1(), four.values()._2()),
                        mk.node2(four.values()._3(), four.values()._4()), m2
                    )
                );
            },
            four1 -> {
                final V4 v1 = four1.values();
                return p2.match(
                    one -> append2(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node2(v1._4(), one.value()), m2),
                    two -> {
                        final V2 v2 = two.values();
                        return append2(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), v2._1(), v2._2()), m2);
                    },
                    three -> {
                        final V3 v2 = three.values();
                        return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node2(v1._4(), v2._1()), mk.node2(v2._2(), v2._3()), m2);
                    },
                    four2 -> {
                        final V4 v2 = four2.values();
                        return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), m2);
                    }
                );
            }
        );
    }

  private static  FingerTree> append1(final Measured m, final FingerTree> xs,
                                                          final Node a, final FingerTree> ys) {
    return xs.match(empty -> ys.cons(a), single -> ys.cons(a).cons(single.value()), deep1 -> ys.match(empty -> xs.snoc(a), single -> xs.snoc(a).snoc(single.value()), deep2 -> {
      final Measured> nm = m.nodeMeasured();
      return new Deep<>(nm, m.sum(m.sum(deep1.v, nm.measure(a)), deep2.v), deep1.prefix,
          addDigits1(nm, deep1.middle, deep1.suffix, a, deep2.prefix, deep2.middle),
          deep2.suffix);
    }));
  }

  private static  FingerTree>> addDigits1(final Measured> m,
                                                                      final FingerTree>> m1,
                                                                      final Digit> x, final Node n,
                                                                      final Digit> y,
                                                                      final FingerTree>> m2) {
    final MakeTree> mk = mkTree(m);
    return x.match(one1 -> y.match(one2 -> append1(m, m1, mk.node3(one1.value(), n, one2.value()), m2), two -> append2(m, m1, mk.node2(one1.value(), n), mk.node2(two.values()), m2), three -> {
      final V3> v2 = three.values();
      return append2(m, m1, mk.node3(one1.value(), n, v2._1()), mk.node2(v2._2(), v2._3()), m2);
    }, four -> {
      final V4> v2 = four.values();
      return append2(m, m1, mk.node3(one1.value(), n, v2._1()), mk.node3(v2._2(), v2._3(), v2._4()), m2);
    }), two1 -> {
      final V2> v1 = two1.values();
      return y.match(one -> append2(m, m1, mk.node2(v1), mk.node2(n, one.value()), m2), two -> append2(m, m1, mk.node3(v1._1(), v1._2(), n), mk.node2(two.values()), m2), three -> append2(m, m1, mk.node3(v1._1(), v1._2(), n), mk.node3(three.values()), m2), four -> {
        final V4> v2 = four.values();
        return append3(m, m1, mk.node3(v1._1(), v1._2(), n), mk.node2(v2._1(), v2._2()), mk.node2(v2._3(), v2._4()),
                       m2);
      });
    }, three -> {
      final V3> v1 = three.values();
      return y.match(one -> append2(m, m1, mk.node3(v1), mk.node2(n, one.value()), m2), two -> {
        final V2> v2 = two.values();
        return append2(m, m1, mk.node3(v1), mk.node3(n, v2._1(), v2._2()), m2);
      }, three1 -> {
        final V3> v2 = three1.values();
        return append3(m, m1, mk.node3(v1), mk.node2(n, v2._1()), mk.node2(v2._2(), v2._3()), m2);
      }, four -> {
        final V4> v2 = four.values();
        return append3(m, m1, mk.node3(v1), mk.node3(n, v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), m2);
      });
    }, four -> {
      final V4> v1 = four.values();
      return y.match(one -> append2(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n, one.value()), m2), two -> append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node2(v1._4(), n), mk.node2(two.values()),
                     m2), three -> {
        final V3> v2 = three.values();
        return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n, v2._1()),
                       mk.node2(v2._2(), v2._3()), m2);
      }, four1 -> {
        final V4> v2 = four1.values();
        return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n, v2._1()),
                       mk.node3(v2._2(), v2._3(), v2._4()), m2);
      });
    });
  }

  private static  FingerTree> append2(final Measured m, final FingerTree> t1,
                                                          final Node n1, final Node n2,
                                                          final FingerTree> t2) {
    return t1.match(empty -> t2.cons(n2).cons(n1), single -> t2.cons(n2).cons(n1).cons(single.value()), deep -> t2.match(empty -> deep.snoc(n1).snoc(n2), single -> deep.snoc(n1).snoc(n2).snoc(single.value()), deep2 -> new Deep<>(m.nodeMeasured(),
        m.sum(m.sum(m.sum(deep.measure(), n1.measure()), n2.measure()),
            deep2.measure()), deep.prefix,
        addDigits2(m.nodeMeasured(), deep.middle, deep.suffix, n1, n2, deep2.prefix,
            deep2.middle), deep2.suffix)));
  }

  private static  FingerTree>> addDigits2(final Measured> m,
                                                                      final FingerTree>> m1,
                                                                      final Digit> suffix,
                                                                      final Node n1, final Node n2,
                                                                      final Digit> prefix,
                                                                      final FingerTree>> m2) {
    final MakeTree> mk = mkTree(m);
    return suffix.match(one -> prefix.match(one2 -> append2(m, m1, mk.node2(one.value(), n1), mk.node2(n2, one2.value()), m2), two -> append2(m, m1, mk.node3(one.value(), n1, n2), mk.node2(two.values()), m2), three -> append2(m, m1, mk.node3(one.value(), n1, n2), mk.node3(three.values()), m2), four -> {
      final V4> v2 = four.values();
      return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node2(v2._1(), v2._2()), mk.node2(v2._3(), v2._4()),
                     m2);
    }), two -> {
      final V2> v1 = two.values();
      return prefix.match(one -> append2(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node2(n2, one.value()), m2), two2 -> {
        final V2> v2 = two2.values();
        return append2(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, v2._1(), v2._2()), m2);
      }, three -> {
        final V3> v2 = three.values();
        return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node2(n2, v2._1()), mk.node2(v2._2(), v2._3()),
                       m2);
      }, four -> {
        final V4> v2 = four.values();
        return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, v2._1(), v2._2()),
                       mk.node2(v2._3(), v2._4()), m2);
      });
    }, three -> {
      final V3> v1 = three.values();
      return prefix.match(one -> append2(m, m1, mk.node3(v1), mk.node3(n1, n2, one.value()), m2), two -> append3(m, m1, mk.node3(v1), mk.node2(n1, n2), mk.node2(two.values()), m2), three2 -> {
        final V3> v2 = three2.values();
        return append3(m, m1, mk.node3(v1), mk.node3(n1, n2, v2._1()), mk.node2(v2._2(), v2._3()), m2);
      }, four -> {
        final V4> v2 = four.values();
        return append3(m, m1, mk.node3(v1), mk.node3(n1, n2, v2._1()), mk.node3(v2._2(), v2._3(), v2._4()), m2);
      });
    }, four -> {
      final V4> v1 = four.values();
      return prefix.match(one -> append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node2(v1._4(), n1), mk.node2(n2, one.value()),
                     m2), two -> append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                     mk.node2(two.values()), m2), three -> append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                     mk.node3(three.values()), m2), four2 -> {
        final V4> v2 = four2.values();
        return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                       mk.node2(v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), m2);
      });
    });
  }

  @SuppressWarnings("unchecked")
  private static  FingerTree> append3(final Measured m, final FingerTree> t1,
                                                          final Node n1, final Node n2, final Node n3,
                                                          final FingerTree> t2) {
    final Measured> nm = m.nodeMeasured();
    return t1.match(empty -> t2.cons(n3).cons(n2).cons(n1), single -> t2.cons(n3).cons(n2).cons(n1).cons(single.value()), deep -> t2.match(empty -> deep.snoc(n1).snoc(n2).snoc(n3), single -> deep.snoc(n1).snoc(n2).snoc(n3).snoc(single.value()), deep2 -> new Deep<>(nm, nm.monoid().sumLeft(
        list(deep.v, n1.measure(), n2.measure(), n3.measure(), deep2.v)), deep.prefix,
        addDigits3(nm, deep.middle, deep.suffix, n1, n2, n3, deep2.prefix,
            deep2.middle), deep2.suffix)));
  }

  private static  FingerTree>> addDigits3(final Measured> m,
                                                                      final FingerTree>> m1,
                                                                      final Digit> suffix,
                                                                      final Node n1, final Node n2,
                                                                      final Node n3,
                                                                      final Digit> prefix,
                                                                      final FingerTree>> m2) {
    final MakeTree> mk = mkTree(m);
    return suffix.match(one -> prefix.match(one2 -> append2(m, m1, mk.node3(one.value(), n1, n2), mk.node2(n3, one2.value()), m2), two -> {
      final V2> v2 = two.values();
      return append2(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, v2._1(), v2._2()), m2);
    }, three -> {
      final V3> v2 = three.values();
      return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node2(n3, v2._1()), mk.node2(v2._2(), v2._3()), m2);
    }, four -> {
      final V4> v2 = four.values();
      return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, v2._1(), v2._2()),
                     mk.node2(v2._3(), v2._4()), m2);
    }), two -> {
      final V2> v1 = two.values();
      return prefix.match(one -> append2(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, one.value()), m2), two1 -> append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node2(n2, n3), mk.node2(two1.values()), m2), three -> {
        final V3> v2 = three.values();
        return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, v2._1()), mk.node2(v2._2(), v2._3()),
                       m2);
      }, four -> {
        final V4> v2 = four.values();
        return append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, v2._1()),
                       mk.node3(v2._2(), v2._3(), v2._4()), m2);
      });
    }, three -> prefix.match(one -> append3(m, m1, mk.node3(three.values()), mk.node2(n1, n2), mk.node2(n3, one.value()), m2), two -> append3(m, m1, mk.node3(three.values()), mk.node3(n1, n2, n3), mk.node2(two.values()), m2), three2 -> append3(m, m1, mk.node3(three.values()), mk.node3(n1, n2, n3), mk.node3(three2.values()), m2), four -> {
      final V4> v2 = four.values();
      return append4(m, m1, mk.node3(three.values()), mk.node3(n1, n2, n3), mk.node2(v2._1(), v2._2()),
                     mk.node2(v2._3(), v2._4()), m2);
    }), four -> {
      final V4> v1 = four.values();
      return prefix.match(one -> append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                     mk.node2(n3, one.value()), m2), two -> {
        final V2> v2 = two.values();
        return append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                       mk.node3(n3, v2._1(), v2._2()), m2);
      }, three -> {
        final V3> v2 = three.values();
        return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2), mk.node2(n3, v2._1()),
                       mk.node2(v2._2(), v2._3()), m2);
      }, four2 -> {
        final V4> v2 = four2.values();
        return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                       mk.node3(n3, v2._1(), v2._2()), mk.node2(v2._3(), v2._4()), m2);
      });
    });
  }

  @SuppressWarnings("unchecked")  
  private static  FingerTree> append4(final Measured m,
                                                          final FingerTree> t1,
                                                          final Node n1,
                                                          final Node n2,
                                                          final Node n3,
                                                          final Node n4,
                                                          final FingerTree> t2) {
    final Measured> nm = m.nodeMeasured();
    return t1.match(empty -> t2.cons(n4).cons(n3).cons(n2).cons(n1), single -> t2.cons(n4).cons(n3).cons(n2).cons(n1).cons(single.value()), deep -> t2.match(empty -> t1.snoc(n1).snoc(n2).snoc(n3).snoc(n4), single -> t1.snoc(n1).snoc(n2).snoc(n3).snoc(n4).snoc(single.value()), deep2 -> new Deep<>(nm, m.monoid().sumLeft(
        list(deep.v, n1.measure(), n2.measure(), n3.measure(), n4.measure(), deep2.v)), deep.prefix,
        addDigits4(nm, deep.middle, deep.suffix, n1, n2, n3, n4, deep2.prefix,
            deep2.middle), deep2.suffix)));
  }

  private static  FingerTree>> addDigits4(final Measured> m,
                                                                      final FingerTree>> m1,
                                                                      final Digit> suffix,
                                                                      final Node n1, final Node n2,
                                                                      final Node n3, final Node n4,
                                                                      final Digit> prefix,
                                                                      final FingerTree>> m2) {
    final MakeTree> mk = mkTree(m);
    return suffix.match(one -> prefix.match(one2 -> append2(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, n4, one2.value()), m2), two -> append3(m, m1, mk.node3(one.value(), n1, n2), mk.node2(n3, n4), mk.node2(two.values()), m2), three -> {
      final V3> v2 = three.values();
      return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, n4, v2._1()), mk.node2(v2._2(), v2._3()),
                     m2);
    }, four -> {
      final V4> v2 = four.values();
      return append3(m, m1, mk.node3(one.value(), n1, n2), mk.node3(n3, n4, v2._1()),
                     mk.node3(v2._2(), v2._3(), v2._4()), m2);
    }), two -> {
      final V2> v1 = two.values();
      return prefix.match(one -> append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node2(n2, n3), mk.node2(n4, one.value()), m2), two2 -> append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, n4), mk.node2(two2.values()), m2), three -> append3(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, n4), mk.node3(three.values()), m2), four -> {
        final V4> v2 = four.values();
        return append4(m, m1, mk.node3(v1._1(), v1._2(), n1), mk.node3(n2, n3, n4), mk.node2(v2._1(), v2._2()),
                       mk.node2(v2._3(), v2._4()), m2);
      });
    }, three -> {
      final V3> v1 = three.values();
      return prefix.match(one -> append3(m, m1, mk.node3(v1), mk.node3(n1, n2, n3), mk.node2(n4, one.value()), m2), two -> {
        final V2> v2 = two.values();
        return append3(m, m1, mk.node3(v1), mk.node3(n1, n2, n3), mk.node3(n4, v2._1(), v2._2()), m2);
      }, three1 -> {
        final V3> v2 = three1.values();
        return append4(m, m1, mk.node3(v1), mk.node3(n1, n2, n3), mk.node2(n4, v2._1()), mk.node2(v2._2(), v2._3()),
                       m2);
      }, four -> {
        final V4> v2 = four.values();
        return append4(m, m1, mk.node3(v1), mk.node3(n1, n2, n3), mk.node3(n4, v2._1(), v2._2()),
                       mk.node2(v2._3(), v2._4()), m2);
      });
    }, four -> {
      final V4> v1 = four.values();
      return prefix.match(one -> append3(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                     mk.node3(n3, n4, one.value()), m2), two -> append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                     mk.node2(n3, n4), mk.node2(two.values()), m2), three -> {
        final V3> v2 = three.values();
        return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                       mk.node3(n3, n4, v2._1()), mk.node2(v2._2(), v2._3()), m2);
      }, four1 -> {
        final V4> v2 = four1.values();
        return append4(m, m1, mk.node3(v1._1(), v1._2(), v1._3()), mk.node3(v1._4(), n1, n2),
                       mk.node3(n3, n4, v2._1()), mk.node3(v2._2(), v2._3(), v2._4()), m2);
      });
    });
  }

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

  public Stream toStream() {
    return prefix().toStream().append(() ->
            middle().match(
                    e -> Stream.nil(),
                    s -> s.value().toStream(),
                    d -> d.toStream().bind(p -> p.toStream())
            )
    ).append(() -> suffix.toStream());
  }

}