
fj.data.Eval 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
The newest version!
package fj.data;
import fj.F;
import fj.F0;
import fj.P;
import fj.P1;
import fj.control.Trampoline;
/**
* Eval
is an abstraction over different models of evaluation.
* The data constructors:
*
* Now
- the value is evaluated immediately.
* Later
- the value is evaluated only once when it's requested (lazy evaluation).
* Always
- the value is evaluated every time when it's requested.
*
*
* Both Later
and Always
are lazy computations, while Now
is eager.
*
*
* @version %build.number%
*/
public abstract class Eval {
/**
* Constructs an eager evaluation by wrapping the given value.
*
* @param a the evaluated value.
* @return an eval with computed value.
*/
public static Eval now(A a) {
return new Now<>(a);
}
/**
* Constructs a lazy evaluation with caching.
*
* @param a the supplier that evaluates a value.
* @return a lazy evaluation.
*/
public static Eval later(F0 a) {
return new Later<>(a);
}
/**
* Constructs a lazy evaluation without caching.
*
* @param a the supplier that evaluates a value.
* @return a lazy evaluation.
*/
public static Eval always(F0 a) {
return new Always<>(a);
}
/**
* Constructs a lazy evaluation of an expression that produces Eval
.
* This operation is stack-safe and can be used for recursive computations.
*
* @param a the supplier that produces an Eval
.
* @return a lazily evaluated nested evaluation.
*/
public static Eval defer(F0> a) {
return new DeferEval<>(a);
}
/**
* Evaluates the computation and return its result.
* Depending on whether the current instance is lazy or eager the
* computation may or may not happen at this point.
*
* @return a result of this computation.
*/
public abstract A value();
/**
* Transforms Eval
into a Eval
using
* the given function.
*
* Note: the computation of the given transformation is always lazy,
* even if it invoked for an eager Now
instance. This computation
* is performed in O(1) stack space.
*
* @param f the transformation function.
* @return a transformed evaluation.
*/
public final Eval map(final F f) {
return bind(a -> now(f.f(a)));
}
/**
* Alias for {@link #bind(F)}.
*/
public final Eval flatMap(final F> f) {
return bind(f);
}
/**
* Transforms Eval
into a Eval
using
* the given function that directly produces Eval
.
*
* Note: the computation of the given transformation is always lazy,
* even if it invoked for an eager Now
instance. This computation
* is performed in O(1) stack space.
*
* @param f the transformation function.
* @return a transformed evaluation.
*/
public final Eval bind(final F> f) {
return new BindTrampolineEval<>(f, asTrampoline());
}
/**
* Transforms the current instance into a trampoline instance.
*/
abstract TrampolineEval asTrampoline();
/**
* Represents an eager computation.
*/
private static final class Now extends Eval {
private final A a;
Now(A a) {
this.a = a;
}
@Override
public final A value() {
return a;
}
@Override
final TrampolineEval asTrampoline() {
return new PureTrampolineEval<>(this);
}
}
/**
* Represents a lazy computation that is evaluated only once.
*/
private static final class Later extends Eval {
private final P1 memo;
Later(F0 producer) {
this.memo = P.hardMemo(producer);
}
@Override
public final A value() {
return memo._1();
}
@Override
final TrampolineEval asTrampoline() {
return new PureTrampolineEval<>(this);
}
}
/**
* Represents a lazy computation that is evaluated every time when it's requested.
*/
private static final class Always extends Eval {
private final F0 supplier;
Always(F0 supplier) {
this.supplier = supplier;
}
@Override
public final A value() {
return supplier.f();
}
@Override
final TrampolineEval asTrampoline() {
return new PureTrampolineEval<>(this);
}
}
/**
* A helper abstraction that allows to perform recursive lazy transformations in O(1) stack space.
*/
private static abstract class TrampolineEval extends Eval {
protected abstract Trampoline trampoline();
@Override
public final A value() {
return trampoline().run();
}
@Override
final TrampolineEval asTrampoline() {
return this;
}
}
private static final class PureTrampolineEval extends TrampolineEval {
private final Eval start;
PureTrampolineEval(Eval start) {
this.start = start;
}
@Override
protected final Trampoline trampoline() {
return Trampoline.suspend(() -> Trampoline.pure(start.value()));
}
}
private static final class BindTrampolineEval extends TrampolineEval {
private final TrampolineEval next;
private final F> f;
BindTrampolineEval(F> f, TrampolineEval next) {
this.next = next;
this.f = f;
}
@Override
protected final Trampoline trampoline() {
return Trampoline.suspend(() -> next.trampoline().bind(v -> f.f(v).asTrampoline().trampoline()));
}
}
private static final class DeferEval extends TrampolineEval {
private final P1> memo;
DeferEval(F0> producer) {
this.memo = P.hardMemo(producer);
}
@Override
protected final Trampoline trampoline() {
return Trampoline.suspend(() -> memo._1().asTrampoline().trampoline());
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy