com.github.tonivade.purefun.monad.Trampoline Maven / Gradle / Ivy
/*
* Copyright (c) 2018-2019, Antonio Gabriel Muñoz Conejo
* Distributed under the terms of the MIT License
*/
package com.github.tonivade.purefun.monad;
import static java.util.Objects.requireNonNull;
import java.util.stream.Stream;
import com.github.tonivade.purefun.Function1;
import com.github.tonivade.purefun.HigherKind;
import com.github.tonivade.purefun.Producer;
import com.github.tonivade.purefun.type.Either;
@HigherKind
public interface Trampoline {
Trampoline apply();
boolean complete();
T get();
default Trampoline map(Function1 map) {
return TrampolineModule.resume(this)
.fold(next -> more(() -> next.map(map)),
value -> done(map.apply(value)));
}
default Trampoline flatMap(Function1> map) {
return TrampolineModule.resume(this)
.fold(next -> more(() -> next.flatMap(map)), map::apply);
}
default R fold(Function1, R> more, Function1 done) {
return complete() ? done.apply(get()) : more.apply(apply());
}
default T run() {
return TrampolineModule.iterate(this).get();
}
TrampolineModule module();
static Trampoline done(T value) {
return new Done<>(value);
}
static Trampoline more(Producer> next) {
return new More<>(next);
}
final class Done implements Trampoline {
final T value;
private Done(T value) {
this.value = requireNonNull(value);
}
@Override
public boolean complete() {
return true;
}
@Override
public T get() {
return value;
}
@Override
public Trampoline apply() {
throw new UnsupportedOperationException();
}
@Override
public TrampolineModule module() {
throw new UnsupportedOperationException();
}
}
final class More implements Trampoline {
final Producer> next;
private More(Producer> next) {
this.next = requireNonNull(next);
}
@Override
public boolean complete() {
return false;
}
@Override
public T get() {
throw new UnsupportedOperationException();
}
@Override
public Trampoline apply() {
return next.get();
}
@Override
public TrampolineModule module() {
throw new UnsupportedOperationException();
}
}
}
interface TrampolineModule {
static Trampoline iterate(Trampoline trampoline) {
return Stream.iterate(trampoline, Trampoline::apply)
.filter(Trampoline::complete).findFirst().orElseThrow(IllegalStateException::new);
}
static Either, T> resume(Trampoline trampoline) {
return trampoline.fold(Either::left, Either::right);
}
} © 2015 - 2025 Weber Informatics LLC | Privacy Policy