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