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

fj.data.Eval Maven / Gradle / Ivy

Go to download

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()); } } }