fj.data.Iteratee Maven / Gradle / Ivy
package fj.data;
import fj.F;
import fj.F0;
import fj.F1Functions;
import fj.Function;
import fj.P;
import fj.P1;
import fj.P2;
import fj.Unit;
/**
*
*/
public final class Iteratee {
/** The input to an iteratee. */
public static abstract 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 final 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 final 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 final 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 static abstract 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 =
new F>, IterV>() {
@Override
public IterV f(final P2> xe) {
final Input e = xe._2();
final F>, IterV> done =
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(done, 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 final 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 final 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 final 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 final 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 final 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 - 2025 Weber Informatics LLC | Privacy Policy