Created
May 22, 2017 13:17
-
-
Save alphaKAI/e0e69559c3e624becd0669194ecff7dd to your computer and use it in GitHub Desktop.
ラムダ式のノーマライザをDで書いてみいた
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
import std.algorithm, | |
std.format, | |
std.array; | |
interface Expr { | |
string stringof(); | |
string[] freeVars(); | |
void replaceIdentifier(string, string); | |
Expr dup(); | |
} | |
class Identifier : Expr { | |
string identifier; | |
this (string identifier) { | |
this.identifier = identifier; | |
} | |
override string stringof() { | |
return this.identifier; | |
} | |
string[] freeVars() { | |
return [this.identifier]; | |
} | |
void replaceIdentifier(string pattern, string newIdentifier) { | |
if (pattern == this.identifier) { | |
this.identifier = newIdentifier; | |
} | |
} | |
Identifier dup() { | |
return new Identifier(this.identifier); | |
} | |
} | |
class Abstraction : Expr { | |
Identifier identifier; | |
Expr expr; | |
this (Identifier identifier, Expr expr) { | |
this.identifier = identifier; | |
this.expr = expr; | |
} | |
override string stringof() { | |
return "(\\%s. %s)".format(this.identifier.stringof, this.expr.stringof); | |
} | |
string[] freeVars() { | |
return expr.freeVars.filter!(x => x != this.identifier.stringof).array; | |
} | |
void replaceIdentifier(string pattern, string newIdentifier) { | |
this.identifier.replaceIdentifier(pattern, newIdentifier); | |
this.expr.replaceIdentifier(pattern, newIdentifier); | |
} | |
Abstraction dup() { | |
return new Abstraction(this.identifier.dup, this.expr.dup); | |
} | |
} | |
bool isIdentifier(Expr expr) { | |
if ((cast(Identifier)expr) !is null) { | |
return true; | |
} else { | |
return false; | |
} | |
} | |
class Application : Expr { | |
Expr car, | |
cdr; | |
this (Expr car, Expr cdr) { | |
this.car = car; | |
this.cdr = cdr; | |
} | |
override string stringof() { | |
string identifier = "%s", | |
others = "(%s)"; | |
string fmt = "%s %s".format(this.car.isIdentifier ? identifier : others, | |
this.cdr.isIdentifier ? identifier : others); | |
return fmt.format(this.car.stringof, this.cdr.stringof); | |
} | |
string[] freeVars() { | |
string[] vars_car = this.car.freeVars, | |
vars_cdr = this.cdr.freeVars; | |
return vars_car ~ vars_cdr.filter!(x => ! vars_car.canFind(x)).array; | |
} | |
void replaceIdentifier(string pattern, string newIdentifier) { | |
this.car.replaceIdentifier(pattern, newIdentifier); | |
this.cdr.replaceIdentifier(pattern, newIdentifier); | |
} | |
Application dup() { | |
return new Application(this.car.dup, this.cdr.dup); | |
} | |
} | |
Identifier ident(string identifier) { | |
return new Identifier(identifier); | |
} | |
Abstraction abst(string identifier, Expr expr) { | |
return new Abstraction(ident(identifier), expr); | |
} | |
Abstraction abst(Identifier identifier, Expr expr) { | |
return new Abstraction(identifier, expr); | |
} | |
Application app(Expr car, Expr cdr) { | |
return new Application(car, cdr); | |
} | |
Identifier freshVar(string identifier, string[] vars) { | |
if (vars.canFind(identifier)) { | |
return freshVar(identifier ~ "x", vars); | |
} else { | |
return ident(identifier); | |
} | |
} | |
Identifier freshVar(Identifier identifier, string[] vars) { | |
return freshVar(identifier.identifier, vars); | |
} | |
Expr substitute(Identifier var, Expr term, Expr expr) { | |
if ((cast(Identifier)expr) !is null) { | |
Identifier identifier = cast(Identifier)expr; | |
string s = identifier.identifier; | |
if (s == var.identifier) { | |
return term; | |
} else { | |
return ident(s); | |
} | |
} else if ((cast(Abstraction)expr) !is null) { | |
Abstraction abstraction = cast(Abstraction)expr; | |
Identifier s = abstraction.identifier.dup; | |
Expr t = abstraction.expr.dup; | |
auto t_vars = t.freeVars, | |
term_vars = term.freeVars; | |
if (s.identifier == var.identifier) { | |
return abst(s, t); | |
} else if (! t_vars.canFind(var.identifier)) { | |
return abst(s, t); | |
} else if (term_vars.canFind(s.identifier)) { | |
auto f = freshVar(s, t_vars ~ term_vars); | |
t.replaceIdentifier(s.identifier, f.identifier); | |
return abst(f, substitute(var, term, t)); | |
} else { | |
return abst(s, substitute(var, term, t)); | |
} | |
} else if ((cast(Application)expr) !is null) { | |
Application appx = cast(Application)expr; | |
Expr s = appx.car, | |
t = appx.cdr; | |
return app(substitute(var.dup, term.dup, s.dup), substitute(var.dup, term.dup, t.dup)); | |
} | |
throw new Exception("Excep!"); | |
} | |
bool is_redex(Expr expr) { | |
if ((cast(Application)expr) !is null && { | |
Application app = cast(Application)expr; | |
return (cast(Abstraction)(app.car)) !is null; | |
}()) { | |
Application app = cast(Application)expr; | |
Abstraction abs = cast(Abstraction)(app.car); | |
Identifier s = abs.identifier; | |
Expr t = abs.expr; | |
Expr u = app.cdr; | |
return true; | |
} else { | |
return false; | |
} | |
} | |
Expr beta_reduce(Expr expr) { | |
if ((cast(Application)expr) !is null && { | |
Application app = cast(Application)expr; | |
return (cast(Abstraction)(app.car)) !is null; | |
}()) { | |
Application app = cast(Application)expr; | |
Abstraction abs = cast(Abstraction)(app.car); | |
Identifier s = abs.identifier.dup; | |
Expr t = abs.expr.dup; | |
Expr u = app.cdr.dup; | |
return substitute(s, u, t); | |
} else { | |
return expr; | |
} | |
} | |
Expr normalize_step(Expr term) { | |
if (term.is_redex) { | |
return normalize(term.beta_reduce.dup); | |
} else { | |
if ((cast(Identifier)term) !is null) { | |
return cast(Identifier)term; | |
} else if ((cast(Abstraction)term) !is null) { | |
Abstraction abstraction = cast(Abstraction)term; | |
Identifier s = abstraction.identifier.dup; | |
Expr t = abstraction.expr.dup; | |
return abst(s, normalize_step(t)); | |
} else if ((cast(Application)term) !is null) { | |
Application appx = cast(Application)term; | |
Expr t = appx.car.dup, | |
u = appx.cdr.dup; | |
auto normalizd_t = normalize_step(t); | |
if (normalizd_t.isEqualExpr(t)) { | |
return app(t, normalize_step(u)); | |
} else { | |
return app(normalizd_t, u).normalize; | |
} | |
} | |
} | |
throw new Exception("Excep!"); | |
} | |
import std.range, | |
std.algorithm, | |
std.string; | |
Expr normalize(Expr term, bool showTerm = false) { | |
if (showTerm) { | |
writeln("normalize -> ", term.stringof); | |
} | |
auto normalizd_term = normalize_step(term); | |
if (normalizd_term.isEqualExpr(term)) { | |
return term; | |
} else { | |
return normalize_step(normalizd_term); | |
} | |
} | |
bool alpha_convertible(Expr term1, Expr term2) { | |
if (((cast(Identifier)term2) !is null)) { | |
string s2 = (cast(Identifier)term2).identifier; | |
if ((cast(Identifier)term1) !is null) { | |
string s1 = (cast(Identifier)term1).identifier; | |
return s1 == s2; | |
} else { | |
return false; | |
} | |
} else if ((cast(Abstraction)term2) !is null) { | |
Abstraction abs2 = cast(Abstraction)term2; | |
auto s2 = abs2.identifier.dup, | |
t2 = abs2.expr.dup; | |
if ((cast(Abstraction)term1) !is null) { | |
Abstraction abs1 = cast(Abstraction)term1; | |
auto s1 = abs1.identifier.dup, | |
t1 = abs1.expr.dup; | |
if (s1 == s2) { | |
return alpha_convertible(t1, t2); | |
} else { | |
return alpha_convertible(t1, substitute(s2, s1, t2)); | |
} | |
} else { | |
return false; | |
} | |
} else if ((cast(Application)term2) !is null) { | |
Application app2 = cast(Application)term2; | |
auto t2 = app2.car.dup, | |
u2 = app2.cdr.dup; | |
if ((cast(Application)term1) !is null) { | |
Application app1 = cast(Application)term1; | |
auto t1 = app1.car.dup, | |
u1 = app1.cdr.dup; | |
return alpha_convertible(t1, t2) && alpha_convertible(u1, u2); | |
} else { | |
return false; | |
} | |
} | |
throw new Exception("Execp!"); | |
} | |
bool isEqualExpr(Expr expr1, Expr expr2) { | |
if (((cast(Identifier)expr1) !is null) && ((cast(Identifier)expr2) !is null)) { | |
string id1 = (cast(Identifier)expr1).identifier, | |
id2 = (cast(Identifier)expr2).identifier; | |
return id1 == id2; | |
} else if ((cast(Abstraction)expr1) !is null) { | |
return alpha_convertible(expr1, expr2); | |
} else if ((cast(Application)expr1) !is null) { | |
return alpha_convertible(expr1, expr2); | |
} | |
return false; | |
} | |
bool isNumber(Expr expr) { | |
if ((cast(Abstraction)expr) !is null && (cast(Abstraction)(cast(Abstraction)expr).expr) !is null) { | |
for (auto z = ((cast(Abstraction)(cast(Abstraction)expr).expr).expr); | |
(cast(Application)z) !is null; z = (cast(Application)z).cdr) { | |
if ((cast(Application)z) is null) { | |
return false; | |
} | |
} | |
return true; | |
} else { | |
return false; | |
} | |
} | |
size_t numberSize(Expr expr) { | |
assert (isNumber(expr)); | |
size_t size; | |
for (auto z = ((cast(Abstraction)(cast(Abstraction)expr).expr).expr); | |
(cast(Application)z) !is null; z = (cast(Application)z).cdr) { | |
size++; | |
} | |
return size; | |
} | |
Abstraction genN(size_t n) { | |
auto f = ident("f"), | |
x = ident("x"), | |
y = ident("y"); | |
Expr ret = abst(f, abst(x, x)); | |
auto succ = abst(y, abst(f, abst(x, app(f, app(app(y, f), x))))); | |
for (size_t i; i < n; i++) { | |
ret = app(succ, ret).normalize; | |
} | |
return cast(Abstraction)ret; | |
} | |
import std.stdio; | |
void main() { | |
auto a = ident("a"), | |
b = ident("b"), | |
f = ident("f"), | |
n = ident("n"), | |
p = ident("p"), | |
q = ident("q"), | |
x = ident("x"), | |
y = ident("y"), | |
z = ident("z"); | |
auto zero = abst(f, abst(x, x)), | |
one = abst(f, abst(x, app(f, x))), | |
two = abst(f, abst(x, app(f, app(f, x)))), | |
three = abst(f, abst(x, app(f, app(f, app(f, x))))); | |
writeln("zero := ", zero.stringof); | |
writeln("one := ", one.stringof); | |
writeln("two := ", two.stringof); | |
writeln("three := ", three.stringof); | |
auto _true = abst(a, abst(b, a)), | |
_false = abst(a, abst(b, b)), | |
_if = abst(f, abst(x, abst(y, app(app(f, x), y)))); | |
writeln("_true := ", _true.stringof); | |
writeln("_false := ", _false.stringof); | |
writeln("_if := ", _if.stringof); | |
writeln("app(app(app(_if, _true), p), q).stringof -> ", app(app(app(_if, _true), p), q).stringof); | |
writeln("app(app(app(_if, _true), p), q).normalize.isEqualExpr(p) -> ", app(app(app(_if, _true), p), q).normalize.isEqualExpr(p)); | |
writeln("app(app(app(_if, _false), p), q).normalize.isEqualExpr(q) -> ", app(app(app(_if, _false), p), q).normalize.isEqualExpr(q)); | |
auto isZero = abst(n, app(app(n, abst(y, _false)), _true)); | |
writeln("isZero := ", isZero.stringof); | |
writeln("app(isZero, zero).isEqualExpr(_true) -> ", app(isZero, zero).normalize.isEqualExpr(_true)); | |
writeln("app(isZero, one).isEqualExpr(_false) -> ", app(isZero, one).normalize.isEqualExpr(_false)); | |
auto cons = abst(x, abst(y, abst(z, app(app(z, x), y)))), | |
car = abst(x, app(x, _true)), | |
cdr = abst(x, app(x, _false)); | |
writeln("cons := ", cons.stringof); | |
writeln("car := ", car.stringof); | |
writeln("cdr := ", cdr.stringof); | |
writeln("app(app(cons, one), two).normalize.stringof -> ", app(app(cons, one), two).normalize.stringof); | |
writeln("app(app(cons, app(app(cons, one), two)), app(app(cons, one), two)).normalize.stringof -> ", app(app(cons, app(app(cons, one), two)), app(app(cons, one), two)).normalize.stringof); | |
auto succ = abst(n, abst(f, abst(x, app(f, app(app(n, f), x))))); | |
writeln("succ := ", succ.stringof); | |
writeln("app(succ, zero).normalize.isEqualExpr(one) -> ", app(succ, zero).normalize.isEqualExpr(one)); | |
auto add = abst(a, abst(b, abst(f, abst(x, app(app(b, f), app(app(a, f), x)))))); | |
writeln("add := ", add.stringof); | |
writeln("app(app(add, one), two).normalize.isEqualExpr(three) -> ", app(app(add, one), two).normalize.isEqualExpr(three)); | |
auto mul = abst(a, abst(b, abst(f, abst(x, app(app(b, app(a, f)), x))))); | |
writeln("mul := ", mul.stringof); | |
writeln("app(app(mul, two), three).normalize.isEqualExpr(genN(6)) -> ", app(app(mul, two), three).normalize.isEqualExpr(genN(6))); | |
auto power = abst(a, abst(b, app(b, a))); | |
writeln("power := ", power.stringof); | |
writeln("app(app(power, three), two).normalize.isEqualExpr(genN(9)) -> ", app(app(power, three), two).normalize.isEqualExpr(genN(9))); | |
auto pred = abst(n, abst(f, abst(x, app(cdr, app(app(n, abst(p, app(app(cons, app(f, app(car, p))), app(car, p)))), | |
app(app(cons, x), x)))))); | |
writeln("pred := ", pred.stringof); | |
writeln("app(pred, three).normalize.isEqualExpr(two) -> ", app(pred, three).normalize.isEqualExpr(two)); | |
writeln("app(pred, zero).normalize.isEqualExpr(zero) -> ", app(pred, zero).normalize.isEqualExpr(zero)); | |
auto Y = abst(f, app(abst(x, app(f, app(x, x))), abst(x, app(f, app(x, x))))); | |
writeln("Y := ", Y.stringof); | |
auto fact_impl = abst(f, abst(n, app(app(app(_if, app(isZero, n)), one), app(app(mul, n), app(f, app(pred, n)))))); | |
auto fact = app(Y, fact_impl); | |
writeln("fact_impl := ", fact_impl.stringof); | |
writeln("fact := ", fact.stringof); | |
//writeln("app(fact, two).normalize.stringof -> ", app(fact, two).normalize(true).stringof); <- これ食わせるとGCが死ぬっぽくてSEGVする。 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment