package com.googlecode.totallylazy; import com.googlecode.totallylazy.functions.*; import com.googlecode.totallylazy.iterators.SegmentIterator; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.Callable; import static com.googlecode.totallylazy.functions.Callables.compose; import static com.googlecode.totallylazy.functions.Functions.returns; import static com.googlecode.totallylazy.Option.some; import static com.googlecode.totallylazy.Unchecked.cast; import static com.googlecode.totallylazy.functions.Lazy1.lazy; public class Computation<T> extends Sequence<T> implements Segment<T>, Memory { private final Lazy<Option<T>> head; private final Lazy1<T, Computation<T>> tail; private Computation(Callable<Option<T>> head, Function1<T, Computation<T>> tail) { this.head = Lazy.lazy(head); this.tail = lazy(tail); } public static <T> Computation<T> computation1(Callable<Option<T>> callable, Function1<T, Computation<T>> next) { return new Computation<T>(callable, next); } public static <T> Computation<T> computation1(T value, Function1<T, Computation<T>> next) { return computation1(returns(some(value)), next); } public static <T> Computation<T> computation(Callable<Option<T>> callable, Function1<? super T, ? extends T> next) { return compute(callable, (T t) -> Option.option(next.call(t))); } public static <T> Computation<T> compute(Callable<Option<T>> callable, Function1<T, Option<T>> call) { return computation1(callable, generate(call)); } public static <T> Computation<T> computation(T value, Function1<? super T, ? extends T> next) { return compute(value, (T t) -> Option.option(next.call(t))); } public static <T> Computation<T> compute(T value, Function1<T, Option<T>> call) { return computation1(value, generate(call)); } public static <T> Computation<T> cons(T value, Computation<T> next) { return computation1(returns(some(value)), Functions.<T, Computation<T>>constant(next)); } public static <T> Computation<T> iterate(final Function1<? super T, ? extends T> callable, final T t) { return computation(t, callable); } public static <T> Computation<T> memoize(final Iterable<? extends T> iterable) { return memorise(iterable); } public static <T> Computation<T> memorise(final Iterable<? extends T> iterable) { Lazy<? extends Iterator<? extends T>> iterator = Lazy.lazy(iterable::iterator); return Computation.<T>computation1( () -> Iterators.headOption(iterator.value()), t -> memorise(iterator.value())); } public static <T> Computation<T> memoize(final Iterator<? extends T> values) { return memorise(values); } public static <T> Computation<T> memorise(final Iterator<? extends T> iterator) { return Computation.<T>computation1( () -> Iterators.headOption(iterator), t -> memorise(iterator)); } public static <T> Function1<T, Computation<T>> generate(final Function1<? super T, ? extends Option<T>> callable) { return value -> computation1(Callables.deferApply(callable, value), generate(callable)); } @Override public Computation<T> cons(T t) { return cons(t, this); } @Override public <C extends Segment<T>> C joinTo(C rest) { return cast(tail().joinTo(rest).cons(head())); } @Override public Sequence<T> empty() { return Sequences.empty(); } @Override public boolean isEmpty() { return head.apply().isEmpty(); } @Override public T head() { return head.value().get(); } @Override public Computation<T> tail() throws NoSuchElementException { return tail.apply(head()); } @Override public Iterator<T> iterator() { return SegmentIterator.iterator(this); } @Override public void forget() { close(); } @Override public void close() { head.close(); tail.close(); } }