Skip to content

Instantly share code, notes, and snippets.

@clinuxrulz
Last active May 17, 2016 03:44
Show Gist options
  • Save clinuxrulz/7cab6c54e53e49ad217de069a5a555e5 to your computer and use it in GitHub Desktop.
Save clinuxrulz/7cab6c54e53e49ad217de069a5a555e5 to your computer and use it in GitHub Desktop.
package com.sm.fp.data.trans;
import com.sm.fp.data.trans.generator.*;
import com.sm.fp.kinds.__;
import com.sm.fp.kinds.__3;
import com.sm.fp.typeclass1.monad.Identity;
import com.sm.fp.typeclass1.monad.Monad;
import com.sm.fp.typeclass1.monad.MonadRec;
import fj.*;
import fj.data.Either;
import fj.data.Option;
import org.derive4j.Data;
import org.derive4j.Flavour;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Created by Clinton on 17/05/2016.
*/
@Data(flavour = Flavour.FJ)
public abstract class GeneratorT<E,M,A> implements __3<GeneratorT.Mu,E,M,A> {
public static class Mu {}
public static <E,M,A> GeneratorT<E,M,A> narrow(__<__<__<GeneratorT.Mu,E>,M>,A> a) {
return (GeneratorT<E,M,A>)a;
}
public interface Cases<R,E,M,A> {
R done(A result);
R emit(E emitValue, GeneratorT<E,M,A> rest);
R bind(Bound<E,M,?,A> bound);
R suspend(F0<GeneratorT<E,M,A>> suspend);
R lift(__<M,A> ma);
}
public abstract <R> R match(Cases<R,E,M,A> cases);
public static class Bound<E,M,A,B> {
private final GeneratorT<E,M,A> _m;
private final F<A,GeneratorT<E,M,B>> _f;
private Bound(GeneratorT<E,M,A> m, F<A,GeneratorT<E,M,B>> f) {
this._m = m;
this._f = f;
}
public static <E,M,A,B> Bound<E,M,A,B> mkBound(GeneratorT<E,M,A> m, F<A,GeneratorT<E,M,B>> f) {
return new Bound(m, f);
}
public GeneratorT<E,M,A> m() {
return _m;
}
public F<A,GeneratorT<E,M,B>> f() {
return _f;
}
}
public __<M,Either<A, P2<E,GeneratorT<E,M,A>>>> run(MonadRec<M> mMonadRec) {
return mMonadRec.tailRecM(
GeneratorTs
.<E,M,A>cases()
.done((A result) -> mMonadRec.pure(Either.<GeneratorT<E,M,A>,Either<A, P2<E,GeneratorT<E,M,A>>>>right(Either.<A,P2<E,GeneratorT<E,M,A>>>left(result))))
.emit((E emitValue, GeneratorT<E, M, A> rest) -> mMonadRec.pure(Either.<GeneratorT<E,M,A>,Either<A, P2<E,GeneratorT<E,M,A>>>>right(Either.<A,P2<E,GeneratorT<E,M,A>>>right(P.p(emitValue, rest)))))
.bind((Bound<E,M,?,A> bound) -> runBound(mMonadRec, bound))
.suspend((suspend) -> mMonadRec.pure(Either.<GeneratorT<E,M,A>,Either<A, P2<E,GeneratorT<E,M,A>>>>left(suspend.f())))
.lift((__<M,A> ma) -> mMonadRec.fmap(
(A a) -> Either.<GeneratorT<E,M,A>,Either<A, P2<E,GeneratorT<E,M,A>>>>right(Either.<A,P2<E,GeneratorT<E,M,A>>>left(a)),
ma
)),
this
);
}
public static <E> Iterator<E> toIterator(GeneratorT<E,Identity.Mu,Unit> generator) {
final Option<P2<E,GeneratorT<E,Identity.Mu,Unit>>> initState = Identity.narrow(generator.run(Identity.monadRec)).run().right().toOption();
return new Iterator<E>() {
private Option<P2<E,GeneratorT<E,Identity.Mu,Unit>>> state = initState;
@Override
public boolean hasNext() {
return state.isSome();
}
@Override
public E next() {
if (state.isNone()) {
throw new NoSuchElementException();
}
P2<E,GeneratorT<E,Identity.Mu,Unit>> x = state.some();
E element = x._1();
state = Identity.narrow(x._2().run(Identity.monadRec)).run().right().toOption();
return element;
}
};
}
public static <E,M,A,B> __<M,Either<GeneratorT<E,M,A>,Either<A,P2<E,GeneratorT<E,M,A>>>>> runBound(Monad<M> mMonad, Bound<E,M,B,A> bound) {
return GeneratorTs
.<E,M,B>cases()
.done((B b) -> mMonad.pure(Either.<GeneratorT<E, M, A>, Either<A, P2<E, GeneratorT<E, M, A>>>>left(bound.f().f(b))))
.emit((E e, GeneratorT<E, M, B> rest) -> mMonad.pure(Either.<GeneratorT<E, M, A>, Either<A, P2<E, GeneratorT<E, M, A>>>>right(Either.<A, P2<E, GeneratorT<E, M, A>>>right(P.p(e, GeneratorT.bind(rest, bound.f()))))))
.bind((Bound<E, M, ?, B> bound2) ->
mMonad.fmap(
(Either<GeneratorT<E, M, B>, Either<B, P2<E, GeneratorT<E, M, B>>>> x) ->
x.<Either<GeneratorT<E, M, A>, Either<A, P2<E, GeneratorT<E, M, A>>>>>either(
(GeneratorT<E, M, B> genB) ->
Either.<GeneratorT<E, M, A>, Either<A, P2<E, GeneratorT<E, M, A>>>>left(GeneratorT.bind(genB, bound.f())),
(Either<B, P2<E, GeneratorT<E, M, B>>> x2) ->
x2.either(
(B b) ->
Either.<GeneratorT<E, M, A>, Either<A, P2<E, GeneratorT<E, M, A>>>>left(bound.f().f(b)),
(P2<E, GeneratorT<E, M, B>> x3) ->
Either.<GeneratorT<E, M, A>, Either<A, P2<E, GeneratorT<E, M, A>>>>right(Either.<A, P2<E, GeneratorT<E, M, A>>>right(P.p(x3._1(), GeneratorT.bind(x3._2(), bound.f()))))
)
),
runBound(mMonad, bound2)
)
)
.suspend((suspend) -> mMonad.pure(Either.left(GeneratorT.bind(suspend.f(), bound.f()))))
.lift((__<M, B> mb) -> mMonad.fmap((B b) -> Either.<GeneratorT<E, M, A>, Either<A, P2<E, GeneratorT<E, M, A>>>>left(bound.f().f(b)), mb))
.f(bound.m());
}
public static <E,M,A> GeneratorT<E,M,A> done(A r) {
return GeneratorTs.done(r);
}
public static <E,M,A> GeneratorT<E,M,A> emit(E a, GeneratorT<E,M,A> rest) {
return GeneratorTs.emit(a, rest);
}
public static <E,M> GeneratorT<E,M,Unit> emit(E e) {
return emit(e, done(Unit.unit()));
}
public static <E,M,A,B> GeneratorT<E,M,B> bind(GeneratorT<E,M,A> ma, F<A,GeneratorT<E,M,B>> f) {
return GeneratorTs
.<E,M,A>cases()
.done((A a) -> f.f(a))
.bind((Bound<E,M,?,A> bound) -> reassociateBind(bound, f))
.otherwise(() -> GeneratorTs.bind(Bound.mkBound(ma, f)))
.f(ma);
}
private static <E,M,A,B,C> GeneratorT<E,M,B> reassociateBind(Bound<E,M,C,A> m, F<A,GeneratorT<E,M,B>> f) {
return suspend(() -> bind(m.m(), (C c) -> bind(m.f().f(c), f)));
}
public static <E,M,A> GeneratorT<E,M,A> suspend(F0<GeneratorT<E,M,A>> a) {
return GeneratorTs.suspend(a);
}
public static <E,M,A> GeneratorT<E,M,A> lift(__<M,A> ma) {
return GeneratorTs.lift(ma);
}
public static <E,M> GeneratorTFunctor<E,M> functor() {
return new GeneratorTFunctor<E,M>() {};
}
public static <E,M> GeneratorTApply<E,M> apply() {
return new GeneratorTApply<E,M>() {};
}
public static <E,M> GeneratorTApplicative<E,M> applicative() {
return new GeneratorTApplicative<E,M>() {};
}
public static <E,M> GeneratorTBind<E,M> bind() {
return new GeneratorTBind<E,M>() {};
}
public static <E,M> GeneratorTMonad<E,M> monad() {
return new GeneratorTMonad<E,M>() {};
}
public static <E,M> GeneratorTMonadTrans<E,M> monadTrans() {
return new GeneratorTMonadTrans<E,M>() {};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment