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

jsonvalues.Trampoline Maven / Gradle / Ivy

package jsonvalues;


import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
 Trampolines allow to define recursive algorithms by iterative loops without blowing the stack when
 methods implementations are tail recursive.

 @param  the type of the result */
public interface Trampoline extends Supplier {

    static  Trampoline done(final T result) {
        return () -> result;
    }

    static  Trampoline more(final Trampoline> trampoline) {
        return new Trampoline() {
            @Override
            public Trampoline bounce() {
                return trampoline.get();
            }

            @Override
            public T get() {
                return trampoline(this);
            }

            @Override
            public boolean complete() {
                return false;
            }

            T trampoline(final Trampoline trampoline) {
                return Stream.iterate(trampoline,
                                      Trampoline::bounce
                                     )
                             .filter(Trampoline::complete)
                             .findFirst()
                             .orElseThrow(UserError::trampolineNotCompleted)
                             .get();
            }
        };
    }

    /**
     maps this trampoline which returns a T, into another one that returns a R. When the method get()
     is invoked, this trampoline is executed and then the result is mapped.

     @param fn  the map function, from T to R
     @param  type of the result
     @return a Trampoline of type R
     */
    default  Trampoline map(Function fn) {
        if (complete()) return done(fn.apply(get()));
        else return Trampoline.more(() -> bounce().map(fn));
    }

    /**
     map this trampoline which returns a T, into another one that returns a R. When the method get()
     is invoked, this trampoline is executed and then the result of type T is passed to the trampoline specified in
     the flatMap function, which will return a R. So, two trampolines are executed, one after the other.

     @param fn  the map function, from T to {@code Trampoline}
     @param  type of the result
     @return a Trampoline of type R
     */
    default  Trampoline flatMap(Function> fn) {
        if (complete()) return fn.apply(get());
        else return Trampoline.more(() -> bounce().flatMap(fn));
    }

    /**
     @return next stage
     */
    default Trampoline bounce() {
        return this;
    }

    /**
     Gets a result

     @return a result
     */
    @Override
    T get();

    default boolean complete() {
        return true;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy