Skip to content

Instantly share code, notes, and snippets.

@mstewartgallus
Created September 5, 2020 00:31
Show Gist options
  • Save mstewartgallus/0073e6d4be4318fac156538878f39ed2 to your computer and use it in GitHub Desktop.
Save mstewartgallus/0073e6d4be4318fac156538878f39ed2 to your computer and use it in GitHub Desktop.
Tagless final style in pure Java using curiously recurring template types.
package com.sstewartgallus;
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
var result = program(new EvalLambdaFactory());
var source = program(new PrettifyLambdaFactory());
System.out.println("Source " + source);
System.out.println("Result " + result);
}
private static <X extends LambdaFactory<X>> LambdaFactory<X>.T<Integer> program(X l) {
var val = l.ofInt(4);
var idA = l.<Integer, Integer>lam(x -> x);
return l.apply(idA, val);
}
}
final class EvalLambdaFactory extends LambdaFactory<EvalLambdaFactory> {
final class IntT extends T<Integer> {
public final int x;
public IntT(int x) {
this.x = x;
}
@Override
public String toString() {
return Integer.toString(x);
}
}
abstract class FnT<A, B> extends T<Function<A, B>> {
public abstract T<B> apply(T<A> x);
}
@Override
public T<Integer> ofInt(int x) {
return new IntT(x);
}
@Override
public <A, B> T<Function<A, B>> lam(Function<T<A>, T<B>> f) {
return new FnT<>() {
@Override
public T<B> apply(T<A> x) {
return f.apply(x);
}
};
}
@Override
public <A, B> T<B> apply(T<Function<A, B>> f, T<A> x) {
var fF = (FnT<A, B>)f;
return fF.apply(x);
}
}
final class PrettifyLambdaFactory extends LambdaFactory<PrettifyLambdaFactory> {
final class StrT<A> extends T<A> {
final String str;
public StrT(String str) {
this.str = str;
}
@Override
public String toString() {
return str;
}
}
@Override
public T<Integer> ofInt(int x) {
return new StrT<>(Integer.toString(x));
}
@Override
public <A, B> T<Function<A, B>> lam(Function<T<A>, T<B>> f) {
var v = "v?";
var body= ((StrT<B>) f.apply(new StrT<>(v))).str;
return new StrT<>("(\\" + v + " -> " + body + ")");
}
@Override
public <A, B> T<B> apply(T<Function<A, B>> f, T<A> x) {
return new StrT<>("(" + f + " " + x + ")");
}
}
abstract class LambdaFactory<Self extends LambdaFactory<Self>> {
public abstract class T<A> {
}
public abstract LambdaFactory<Self>.T<Integer> ofInt(int x);
public abstract <A, B> LambdaFactory<Self>.T<Function<A, B>> lam(Function<LambdaFactory<Self>.T<A>,
LambdaFactory<Self>.T<B>> f);
public abstract <A, B> LambdaFactory<Self>.T<B> apply(LambdaFactory<Self>.T<Function<A, B>> f,
LambdaFactory<Self>.T<A> x);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment