Skip to content

Instantly share code, notes, and snippets.

@dvanhorn
Last active August 29, 2015 14:18
Show Gist options
  • Save dvanhorn/005d3b5f5791f97d7864 to your computer and use it in GitHub Desktop.
Save dvanhorn/005d3b5f5791f97d7864 to your computer and use it in GitHub Desktop.
Definitional interp without closures in Java
interface Exp {
<A> A visit(ExpVisitor<A> v);
}
interface Val {
Val apply(Val a);
Integer n();
}
abstract class AVal implements Val {
public Val apply(Val a) {
throw new RuntimeException("Not a function");
}
public Integer n() {
throw new RuntimeException("Not a number");
}
}
abstract class Env {
public Env extend(String x, Val v) {
return new Ext(x, v, this);
}
abstract public Val lookup(String x);
}
class Mt extends Env {
Mt() {}
public Val lookup(String x) {
throw new RuntimeException("No such binding");
}
}
class Ext extends Env {
String x;
Val v;
Env r;
Ext(String x, Val v, Env r) {
this.x = x;
this.v = v;
this.r = r;
}
public Val lookup(String y) {
return y.equals(this.x) ?
this.v : this.r.lookup(y);
}
}
interface ExpVisitor<A> {
A var(String x);
A num(Integer n);
A app(Exp e1, Exp e2);
A lam(String x, Exp e);
A ifz(Exp e1, Exp e2, Exp e3);
}
class Var implements Exp {
String x;
Var(String x) {
this.x = x;
}
public <A> A visit(ExpVisitor<A> v) {
return v.var(this.x);
}
}
class Num extends AVal implements Exp, Val {
Integer n;
Num(Integer n) {
this.n = n;
}
public <A> A visit(ExpVisitor<A> v) {
return v.num(this.n);
}
public Integer n() { return this.n; }
public String toString() { return this.n.toString(); }
}
class Lam implements Exp {
String x;
Exp e;
Lam(String x, Exp e) {
this.x = x;
this.e = e;
}
public <A> A visit(ExpVisitor<A> v) {
return v.lam(this.x, this.e);
}
}
class App implements Exp {
Exp e1;
Exp e2;
App(Exp e1, Exp e2) {
this.e1 = e1;
this.e2 = e2;
}
public <A> A visit(ExpVisitor<A> v) {
return v.app(this.e1, this.e2);
}
}
class If implements Exp {
Exp e1;
Exp e2;
Exp e3;
If(Exp e1, Exp e2, Exp e3) {
this.e1 = e1;
this.e2 = e2;
this.e3 = e3;
}
public <A> A visit(ExpVisitor<A> v) {
return v.ifz(this.e1, this.e2, this.e3);
}
}
// The eval "function"
class Eval implements ExpVisitor<Val> {
Env r;
Eval(Env r) {
this.r = r;
}
public Val var(String x) { return this.r.lookup(x); }
public Val num(Integer n) { return new Num(n); }
public Val app(Exp e1, Exp e2) {
return e1.visit(this).apply(e2.visit(this));
}
public Val lam(String x, Exp e) {
return new AVal() {
public Val apply(Val a) {
return e.visit(new Eval(r.extend(x,a)));
}
};
}
public Val ifz(Exp e1, Exp e2, Exp e3) {
return e1.visit(this).n().equals(0) ? e2.visit(this) : e3.visit(this);
}
}
class Interp {
public static void main(String[] xs) {
Val sub1 =
new AVal() {
public Val apply(Val n) {
return new AVal() {
public Integer n() { return n.n() - 1; }
};
}
};
Val times =
new AVal() {
public Val apply(Val n) {
return new AVal() {
public Val apply(Val m) {
return new Num(n.n() * m.n());
};
};
}
};
// Y combinator
Exp y1 =
new Lam("x",
new App(new Var("f"),
new Lam("y",
new App(new App(new Var("x"),
new Var("x")),
new Var("y")))));
Exp rec =
new Lam("f", new App(y1, y1));
Exp fact =
new App(rec,
new Lam("fact",
new Lam("n",
new If(new Var("n"),
new Num(1),
new App(new App(new Var("times"),
new Var("n")),
new App(new Var("fact"),
new App(new Var("sub1"),
new Var("n"))))))));
Env r = new Ext("sub1", sub1, new Ext("times", times, new Mt()));
System.out.println(new App(fact, new Num(5)).visit(new Eval(r)));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment