Created
September 5, 2020 00:31
-
-
Save mstewartgallus/0073e6d4be4318fac156538878f39ed2 to your computer and use it in GitHub Desktop.
Tagless final style in pure Java using curiously recurring template types.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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