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

fj.data.Iteratee 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;

import fj.F;
import fj.F0;
import fj.F1Functions;
import fj.Function;
import fj.P;
import fj.P2;
import fj.Unit;

/**
 * 
 */
public final class Iteratee {

  /** The input to an iteratee. */
  public abstract static class Input {

    Input() {} // sealed

    public abstract  Z apply(final F0 empty, final F0> el, final F0 eof);

    /** Input that has no values available */
    public static  Input empty() {
      return new Input() {
        @Override
        public  Z apply(final F0 empty, final F0> el, final F0 eof) {
          return empty.f();
        }
      };
    }

    /** Input that is exhausted */
    public static  Input eof() {
      return new Input() {
        @Override
        public  Z apply(final F0 empty, final F0> el, final F0 eof) {
          return eof.f();
        }
      };
    }

    /** Input that has a value available */
    public static  Input el(final E element) {
      return new Input() {
        @Override
        public  Z apply(final F0 empty, final F0> el, final F0 eof) {
          return el.f().f(element);
        }
      };
    }
  }

  /** A pure iteratee computation which is either done or needs more input */
  public abstract static class IterV {

    IterV() {} // sealed

    /** A computation that takes an element from an input to yield a new computation */
    public static  IterV cont(final F, IterV> f) {
      return new IterV() {
        @Override
        public  Z fold(final F>, Z> done, final F, IterV>, Z> cont) {
          return cont.f(f);
        }
      };
    }

    public abstract  Z fold(final F>, Z> done, final F, IterV>, Z> cont);

    /** A computation that has finished */
    public static  IterV done(final A a, final Input i) {
      final P2> p = P.p(a, i);
      return new IterV() {
        @Override
        public  Z fold(final F>, Z> done, final F, IterV>, Z> cont) {
          return done.f(p);
        }
      };
    }

    public final A run() {
      final F, Option> runCont =
        new F, Option>() {
          final F>, Option> done = F1Functions.andThen(P2.__1(), Option.some_());
          final F, IterV>, Option> cont = Function.constant(Option.none());

          @Override
          public Option f(final IterV i) {
            return i.fold(done, cont);
          }
        };
      final F>, A> done = P2.__1();
      final F, IterV>, A> cont =
              k -> runCont.f(k.f(Input.eof())).valueE("diverging iteratee");
      return fold(done, cont);
    }

    /** TODO more documentation */
    public final  IterV bind(final F> f) {
      final F>, IterV> done =
          xe -> {
            final Input e = xe._2();
            final F>, IterV> done1 =
                    y_ -> {
                      final B y = y_._1();
                      return done(y, e);
                    };
            final F, IterV>, IterV> cont =
                    k -> k.f(e);
            final A x = xe._1();
            return f.f(x).fold(done1, cont);
          };
      final F, IterV>, IterV> cont =
              k -> cont(e -> k.f(e).bind(f));
      return this.fold(done, cont);
    }

    /** An iteratee that counts and consumes the elements of the input */
    public static  IterV length() {
      final F, IterV>> step =
        new F, IterV>>() {
          final F, IterV>> step = this;

          @Override
          public F, IterV> f(final Integer acc) {
            final F0> empty = () -> cont(step.f(acc));

            final F0>> el = () -> P.p(cont(step.f(acc + 1))).constant();

            final F0> eof = () -> done(acc, Input.eof());

            return s -> s.apply(empty, el, eof);
          }
        };
      return cont(step.f(0));
    }

    /** An iteratee that skips the first n elements of the input */
    public static  IterV drop(final int n) {
      final F, IterV> step =
        new F, IterV>() {
          final F, IterV> step = this;

          final F0> empty = () -> cont(step);

          final F0>> el = () -> P.p(IterV.drop(n - 1)).constant();
          
          final F0> eof = () -> done(Unit.unit(), Input.eof());

          @Override
          public IterV f(final Input s) {
            return s.apply(empty, el, eof);
          }
        };
      return n == 0
        ? done(Unit.unit(), Input.empty())
        : cont(step);
    }

    /** An iteratee that consumes the head of the input */
    public static  IterV> head() {
      final F, IterV>> step =
        new F, IterV>>() {
          final F, IterV>> step = this;

          final F0>> empty = () -> cont(step);

          final F0>>> el = () -> e -> done(Option.some(e), Input.empty());

          final F0>> eof = () -> done(Option.none(), Input.eof());

          @Override
          public IterV> f(final Input s) {
            return s.apply(empty, el, eof);
          }
        };
      return cont(step);
    }

    /** An iteratee that returns the first element of the input */
    public static  IterV> peek() {
      final F, IterV>> step =
        new F, IterV>>() {
          final F, IterV>> step = this;

          final F0>> empty = () -> cont(step);

          final F0>>> el = () -> e -> done(Option.some(e), Input.el(e));

          final F0>> eof = () -> done(Option.none(), Input.eof());

          @Override
          public IterV> f(final Input s) {
            return s.apply(empty, el, eof);
          }
        };
      return cont(step);
    }

    /** An iteratee that consumes the input elements and returns them as a list in reverse order,
     * so that the last line is the first element. This allows to build a list from 2 iteratees. */
    public static  IterV> list() {
        final F, F, IterV>>> step =
          new F, F, IterV>>>() {
            final F, F, IterV>>> step = this;

            @Override
            public F, IterV>> f(final List acc) {
              final F0>> empty = () -> cont(step.f(acc));

              final F0>>> el = () -> e -> cont(step.f(acc.cons(e)));

              final F0>> eof = () -> done(acc, Input.eof());

              return s -> s.apply(empty, el, eof);
            }
          };
        return cont(step.f(List.nil()));
    }
  }

  private Iteratee() {
    throw new UnsupportedOperationException();
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy