diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/Example.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/Example.java new file mode 100644 index 000000000..5c4500c5d --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/Example.java @@ -0,0 +1,139 @@ +package com.jnape.palatable.lambda.monad.transformer.interpreter; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.io.IO; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.builtin.*; +import com.jnape.palatable.lambda.monad.transformer.interpreter.interpreters.Transformers; +import com.jnape.palatable.lambda.monoid.Monoid; + +import static com.jnape.palatable.lambda.adt.Either.left; +import static com.jnape.palatable.lambda.adt.Either.right; +import static com.jnape.palatable.lambda.adt.Maybe.just; +import static com.jnape.palatable.lambda.adt.Maybe.nothing; +import static com.jnape.palatable.lambda.adt.hlist.HList.tuple; +import static com.jnape.palatable.lambda.io.IO.io; +import static com.jnape.palatable.lambda.monad.transformer.builtin.EitherT.eitherT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT.identityT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.IterateT.unfold; +import static com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT.maybeT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.ReaderT.readerT; +import static com.jnape.palatable.lambda.monad.transformer.builtin.StateT.liftStateT; +import static com.jnape.palatable.lambda.monad.transformer.interpreter.InterpreterH.InterpreterHs.interpretIdentityT; +import static com.jnape.palatable.lambda.monad.transformer.interpreter.InterpreterH.lifting; +import static com.jnape.palatable.lambda.monad.transformer.interpreter.interpreters.Transformers.*; +import static com.jnape.palatable.lambda.monad.transformer.interpreter.interpreters.transformers.Construction.eitherT; +import static com.jnape.palatable.lambda.monoid.Monoid.monoid; + +public class Example { + public static void simpleCase() { + EitherT, String, Integer> eitherT = eitherT(io(() -> right(1))); + Transformers., String, Integer>runEitherT() + .>>interpret(eitherT) + .flatMap(res -> io(() -> System.out.println("res (" + res.getClass().getName() + "): " + res))) + .unsafePerformIO(); + } + + public static void nested() { + EitherT, ?>, String, Integer> effect = + eitherT(maybeT(io(() -> just(left("yeh nah"))))); + + Interpreter, ?>, String, ?>, Integer, IO, Maybe>> voila = + Transformers., ?>, String, Integer>runEitherT() + .andThen(runMaybeT()); + + voila + .>>>interpret(effect) + .flatMap(res -> io(() -> System.out.println("res (" + res.getClass().getName() + "): " + res))) + .unsafePerformIO(); + } + + public static void deeplyNested() { + Fn1 recoveryFn = String::length; + Fn0 orElseGet = () -> -1; + + Interpreter, ?>, ?>, String, ?>, Integer, IO, Integer> interpreter = + Transformers., ?>, ?>, String, Integer>interpretEitherT(recoveryFn) + .andThen(interpretMaybeT(orElseGet)) + .andThen(interpretIdentityT()); + + interpreter + .>interpret(eitherT(maybeT(identityT(io(() -> new Identity<>(just(right(42)))))))) + .flatMap(res -> io(() -> System.out.println("res (" + res.getClass().getName() + "): " + res))) + .unsafePerformIO(); + } + + public static void readerTCase() { + ReaderT, String, ?>, Integer> transactional = + readerT(f -> eitherT(f ? io(() -> right((int) Math.round(Math.random() * 100))) : io(left("foo")))); + + // F a -> G b + Interpreter< + // F a + ReaderT, String, ?>, ?>, Integer, + // G b + IO, Tuple2, Integer> + > massiveInterpreter = + Transformers + ., String, ?>>runReaderT(true) + ., Integer, Either>andThen(runEitherT()) + ., ?>>andThen(lifting(liftStateT())) + .andThen(eitherT()) + .andThen(runEitherT()) + .andThen(runStateT(10)); + + massiveInterpreter + ., Integer>>>interpret(transactional) + .flatMap(res -> io(() -> System.out.println("res (" + res.getClass().getName() + "): " + res))) + .unsafePerformIO(); + } + + public static void main(String[] args) { + simpleCase(); + nested(); + deeplyNested(); + readerTCase(); + iterateTCase(); + } + + public static , A> Interpreter, A, M, A> folding(Monoid monoid) { + return new Interpreter, A, M, A>() { + @Override + public > GB interpret(MonadRec> fa) { + IterateT ma = fa.coerce(); + MonadRec>>, M> mmta = ma.runIterateT(); + return ma.fold((a, b) -> mmta.pure(monoid.apply(a, b)), + mmta.pure(monoid.identity())); + } + }; + } + + public static , A> Interpreter, A, M, Maybe> head() { + return new Interpreter, A, M, Maybe>() { + @Override + public , M>> GB interpret(MonadRec> fa) { + return fa.>coerce().runIterateT().fmap(m -> m.fmap(Tuple2::_1)).coerce(); + } + }; + } + + private static void iterateTCase() { + Example., Integer>folding(monoid(Integer::sum, 0)) + .compose(runReaderT(true)) + .>interpret(readerT(b -> unfold(x -> io(() -> { + System.out.print("reading " + x + "..."); + return x ? just(tuple(1, false)) : nothing(); + }), + io(() -> { + System.out.print("seed..."); + return b; + })))) + .flatMap(res -> io(() -> System.out.println("res (" + res.getClass().getName() + "): " + res))) + .unsafePerformIO(); + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/Interpreter.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/Interpreter.java new file mode 100644 index 000000000..28f85a996 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/Interpreter.java @@ -0,0 +1,65 @@ +package com.jnape.palatable.lambda.monad.transformer.interpreter; + +import com.jnape.palatable.lambda.functions.specialized.Lift; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.MonadT; + +public interface Interpreter, A, G extends MonadRec, B> { + + > GB interpret(MonadRec fa); + + @SuppressWarnings("overloads") + default , C> Interpreter andThen(Interpreter ghbc) { + return new Interpreter() { + @Override + public > HC interpret(MonadRec fa) { + return ghbc.interpret(Interpreter.this.interpret(fa)); + } + }; + } + + @SuppressWarnings("overloads") + default > Interpreter andThen(InterpreterH gh) { + return new Interpreter() { + @Override + public > GB interpret(MonadRec fa) { + return gh.interpretH(Interpreter.this.interpret(fa)); + } + }; + } + + @SuppressWarnings("overloads") + default , Z> Interpreter compose(Interpreter efza) { + return efza.andThen(this); + } + + @SuppressWarnings("overloads") + default > Interpreter compose(InterpreterH ef) { + return new Interpreter() { + @Override + public > GB interpret(MonadRec ea) { + return Interpreter.this.interpret(ef.interpretH(ea)); + } + }; + } + + static , A> Interpreter identity() { + //noinspection Anonymous2MethodRef + return new Interpreter() { + @Override + public > GB interpret(MonadRec fa) { + return fa.coerce(); + } + }; + } + + static , T extends MonadT, G extends MonadT, A> + Interpreter lifting(Lift liftT) { + return new Interpreter() { + @Override + public > GB interpret(MonadRec fa) { + return liftT.>apply(fa).coerce(); + } + }; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/InterpreterH.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/InterpreterH.java new file mode 100644 index 000000000..a8a003fd1 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/InterpreterH.java @@ -0,0 +1,86 @@ +package com.jnape.palatable.lambda.monad.transformer.interpreter; + +import com.jnape.palatable.lambda.functions.specialized.Lift; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.MonadT; +import com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT; + +public interface InterpreterH, G extends MonadRec> { + + > GA interpretH(MonadRec fa); + + default > InterpreterH andThenH(InterpreterH gh) { + return new InterpreterH() { + @Override + public > HA interpretH(MonadRec fa) { + return gh.interpretH(InterpreterH.this.interpretH(fa)); + } + }; + } + + default , A, B> Interpreter andThen(Interpreter gh) { + return gh.compose(this); + } + + default > InterpreterH composeH(InterpreterH ef) { + return ef.andThenH(this); + } + + default , A, B> Interpreter compose(Interpreter gh) { + return gh.andThen(this); + } + + default Interpreter monomorphize() { + return new Interpreter() { + @Override + public > GA interpret(MonadRec fa) { + return interpretH(fa); + } + }; + } + + static > InterpreterH identity() { + return new InterpreterH() { + @Override + public > GA interpretH(MonadRec fa) { + return fa.coerce(); + } + }; + } + + static , T extends MonadT, G extends MonadT> InterpreterH + lifting(Lift liftT) { + return new InterpreterH() { + @Override + public > GA interpretH(MonadRec fa) { + return liftT.>apply(fa).coerce(); + } + }; + } + + static , T extends MonadT, G extends MonadT> InterpreterH + constructing(Lift liftT) { + return new InterpreterH() { + @Override + public > GA interpretH(MonadRec fa) { + return liftT.>apply(fa).coerce(); + } + }; + } + + final class InterpreterHs { + private InterpreterHs() { + } + + public static > InterpreterH, F> interpretIdentityT() { + return new InterpreterH, F>() { + @Override + public > GA interpretH(MonadRec> fa) { + return fa.>coerce().runIdentityT().fmap(Identity::runIdentity).coerce(); + } + }; + } + } + +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/Transformers.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/Transformers.java new file mode 100644 index 000000000..1fed523e3 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/Transformers.java @@ -0,0 +1,82 @@ +package com.jnape.palatable.lambda.monad.transformer.interpreter.interpreters; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.builtin.*; +import com.jnape.palatable.lambda.monad.transformer.interpreter.Interpreter; +import com.jnape.palatable.lambda.monad.transformer.interpreter.InterpreterH; + +import static com.jnape.palatable.lambda.monad.transformer.interpreter.interpreters.Values.*; + +public final class Transformers { + private Transformers() { + } + + public static , L, R> Interpreter, R, F, Either> runEitherT() { + return new Interpreter, R, F, Either>() { + @Override + public , F>> GB interpret(MonadRec> fa) { + return fa.>coerce().runEitherT(); + } + }; + } + + public static , L, R> Interpreter, R, F, R> interpretEitherT( + Fn1 recoveryFn) { + return Transformers.runEitherT().andThen(interpretEither(recoveryFn)); + } + + + public static , A> Interpreter, A, F, Maybe> runMaybeT() { + return new Interpreter, A, F, Maybe>() { + @Override + public , F>> FMA interpret(MonadRec> maybeT) { + return maybeT.>coerce().runMaybeT(); + } + }; + } + + public static , A> Interpreter, A, F, A> interpretMaybeT(Fn0 orElse) { + return Transformers.runMaybeT().andThen(interpretMaybe(orElse)); + } + + + public static , A> Interpreter, A, F, Identity> runIdentityT() { + return new Interpreter, A, F, Identity>() { + @Override + public , F>> GB interpret(MonadRec> fa) { + return fa.>coerce().runIdentityT(); + } + }; + } + + public static , A> Interpreter, A, F, A> interpretIdentityT() { + return Transformers.runIdentityT().andThen(interpretIdentity()); + } + + public static > InterpreterH, M> runReaderT(R r) { + return new InterpreterH, M>() { + @Override + public > GA interpretH(MonadRec> fa) { + return fa.>coerce().runReaderT(r); + } + }; + } + + public static , A> Interpreter, A, M, Tuple2> runStateT(S s) { + return new Interpreter, A, M, Tuple2>() { + @Override + public , M>> GB interpret(MonadRec> fa) { + return fa.>coerce().runStateT(s).coerce(); + } + }; + } + + public static void main(String[] args) { + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/Values.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/Values.java new file mode 100644 index 000000000..934cabf81 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/Values.java @@ -0,0 +1,55 @@ +package com.jnape.palatable.lambda.monad.transformer.interpreter.interpreters; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.adt.hlist.Tuple2; +import com.jnape.palatable.lambda.functions.Fn0; +import com.jnape.palatable.lambda.functions.Fn1; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.functor.builtin.Writer; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.interpreter.Interpreter; +import com.jnape.palatable.lambda.monoid.Monoid; + +public final class Values { + private Values() { + } + + public static , L, R> Interpreter, F, R> + interpretEither(Fn1 recoveryFn) { + return new Interpreter, F, R>() { + @Override + public > GB interpret(MonadRec, F> fa) { + return fa.fmap(lOrR -> lOrR.recover(recoveryFn)).coerce(); + } + }; + } + + public static , A> Interpreter, F, A> interpretMaybe(Fn0 orElse) { + return new Interpreter, F, A>() { + @Override + public > GB interpret(MonadRec, F> fa) { + return fa.fmap(maybeA -> maybeA.orElseGet(orElse)).coerce(); + } + }; + } + + public static , A> Interpreter, F, A> interpretIdentity() { + return new Interpreter, F, A>() { + @Override + public > GB interpret(MonadRec, F> fa) { + return fa.fmap(Identity::runIdentity).coerce(); + } + }; + } + + public static , W, A> Interpreter, F, Tuple2> + interpretWriter(Monoid monoidW) { + return new Interpreter, F, Tuple2>() { + @Override + public , F>> GB interpret(MonadRec, F> fa) { + return fa.fmap(writer -> writer.runWriter(monoidW)).coerce(); + } + }; + } +} diff --git a/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/transformers/Construction.java b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/transformers/Construction.java new file mode 100644 index 000000000..9dda75ed7 --- /dev/null +++ b/src/main/java/com/jnape/palatable/lambda/monad/transformer/interpreter/interpreters/transformers/Construction.java @@ -0,0 +1,42 @@ +package com.jnape.palatable.lambda.monad.transformer.interpreter.interpreters.transformers; + +import com.jnape.palatable.lambda.adt.Either; +import com.jnape.palatable.lambda.adt.Maybe; +import com.jnape.palatable.lambda.functor.builtin.Identity; +import com.jnape.palatable.lambda.monad.MonadRec; +import com.jnape.palatable.lambda.monad.transformer.builtin.EitherT; +import com.jnape.palatable.lambda.monad.transformer.builtin.IdentityT; +import com.jnape.palatable.lambda.monad.transformer.builtin.MaybeT; +import com.jnape.palatable.lambda.monad.transformer.interpreter.Interpreter; + +public final class Construction { + private Construction() { + } + + public static , A> Interpreter, MaybeT, A> maybeT() { + return new Interpreter, MaybeT, A>() { + @Override + public >> GB interpret(MonadRec, F> fa) { + return MaybeT.maybeT(fa).coerce(); + } + }; + } + + public static , L, R> Interpreter, EitherT, R> eitherT() { + return new Interpreter, EitherT, R>() { + @Override + public >> GB interpret(MonadRec, F> fa) { + return EitherT.eitherT(fa).coerce(); + } + }; + } + + public static , A> Interpreter, IdentityT, A> identityT() { + return new Interpreter, IdentityT, A>() { + @Override + public >> GB interpret(MonadRec, F> fa) { + return IdentityT.identityT(fa).coerce(); + } + }; + } +}