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

com.github.tonivade.purefun.free.Trampoline Maven / Gradle / Ivy

/*
 * Copyright (c) 2018-2020, Antonio Gabriel Muñoz Conejo 
 * Distributed under the terms of the MIT License
 */
package com.github.tonivade.purefun.free;

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 {

    private 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 {

    private 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