Skip to content

Instantly share code, notes, and snippets.

@Superstar64
Last active November 26, 2021 04:05
Show Gist options
  • Save Superstar64/6d4baf534d8ea2e774053bcc9eed3cdb to your computer and use it in GitHub Desktop.
Save Superstar64/6d4baf534d8ea2e774053bcc9eed3cdb to your computer and use it in GitHub Desktop.
Freer Monads in java
import java.util.function.Function;
// straight forward port of freer monads to java
// see http://okmij.org/ftp/Computation/free-monad.html
// lightweight higher kinded polymorphism
// see http://ocamllabs.io/higher/lightweight-higher-kinded-polymorphism.pdf
interface App<F,A> {}
// freer monads have an exstential type
// so pattern matching on them requires a rank n type
interface View<R, F, A> {
R pure(A pure);
<X> R impure(App<F, X> now, Function<X, Freer<F, A>> after);
}
// the 2 constructors for freer monads
class Pure<F, A> extends Freer<F, A> {
final A pure;
Pure(A pure) {
this.pure = pure;
}
<R> R match(View<R, F, A> view) {
return view.pure(pure);
}
}
class Impure<X, F, A> extends Freer<F, A> {
final App<F, X> now;
final Function<X, Freer<F,A>> after;
Impure(App<F, X> now, Function<X, Freer<F, A>> after) {
this.now = now;
this.after = after;
}
<R> R match(View<R, F, A> view) {
return view.impure(now, after);
}
}
public abstract class Freer<F, A> implements App<App<Freer<?, ?>, F>, A> {
abstract <R> R match(View<R, F, A> view);
// monadic bind
final <B> Freer<F, B> flatMap(Function<A, Freer<F, B>> lastly) {
return match(new View<Freer<F, B>, F, A>() {
public Freer<F, B> pure(A pure) {
return lastly.apply(pure);
}
public <X> Freer<F, B> impure(App<F, X> now, Function<X, Freer<F, A>> after) {
return new Impure<X, F, B>(now, x -> after.apply(x).flatMap(lastly) );
}
});
}
// convert a F a to Freer F a
static <F, A> Freer<F, A> eta(App<F, A> effect) {
return impure(effect, Freer::pure);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment