Skip to content

Commit eb7a935

Browse files
committed
port of python blc (binary lambda calculus)
1 parent f53c920 commit eb7a935

File tree

1 file changed

+214
-0
lines changed

1 file changed

+214
-0
lines changed

blc.php

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
<?php
2+
3+
/*
4+
Binary Lambda Calculus
5+
6+
e : 00 e (Lam)
7+
| 01 e e (App)
8+
| [1] 0 (Var)
9+
10+
Var encodes DeBruijn indices with
11+
12+
0 = 10
13+
1 = 110
14+
2 = 1110
15+
3 = 11110
16+
...
17+
18+
Closure : TE Term Env
19+
| IDX Int
20+
21+
Env : [Closure]
22+
23+
[[e]] = Return Closure | Apply Term Term Env
24+
25+
*/
26+
27+
// based on the python implementation:
28+
// https://github.com/sdiehl/bnlc
29+
//
30+
// other references:
31+
// * http://stackoverflow.com/q/18034246
32+
33+
#------------------------------------------------------------------------
34+
# Structures
35+
#------------------------------------------------------------------------
36+
37+
class App
38+
{
39+
function __construct($e1, $e2)
40+
{
41+
$this->e1 = $e1;
42+
$this->e2 = $e2;
43+
}
44+
45+
function __toString()
46+
{
47+
return sprintf('%s(%s)', $this->e1, $this->e2);
48+
}
49+
}
50+
51+
class Lam
52+
{
53+
function __construct($e)
54+
{
55+
$this->e = $e;
56+
}
57+
58+
function __toString()
59+
{
60+
return sprintf('\%s', $this->e);
61+
}
62+
}
63+
64+
class BVar
65+
{
66+
function __construct($i)
67+
{
68+
$this->i = $i;
69+
}
70+
71+
function __toString()
72+
{
73+
return (string) $this->i;
74+
}
75+
}
76+
77+
class BReturn
78+
{
79+
function __construct($cls)
80+
{
81+
$this->cls = $cls;
82+
}
83+
}
84+
85+
class Apply
86+
{
87+
function __construct($e1, $e2, $env)
88+
{
89+
$this->e1 = $e1;
90+
$this->e2 = $e2;
91+
$this->env = $env;
92+
}
93+
}
94+
95+
class Idx
96+
{
97+
function __construct($i)
98+
{
99+
$this->i = $i;
100+
}
101+
}
102+
103+
class TE
104+
{
105+
function __construct($term, $env)
106+
{
107+
$this->term = $term;
108+
$this->env = $env;
109+
}
110+
}
111+
112+
#------------------------------------------------------------------------
113+
# Normalization
114+
#------------------------------------------------------------------------
115+
116+
function span($p, $xs)
117+
{
118+
for ($i = 0; $i < strlen($xs); $i++) {
119+
$x = $xs[$i];
120+
121+
if (!$p($x)) {
122+
return [substr($xs, 0, $i), substr($xs, $i)];
123+
}
124+
}
125+
return [[], $xs];
126+
}
127+
128+
function parse($xs)
129+
{
130+
if ($xs[0] == '0' && $xs[1] == '0') {
131+
list($t, $xs) = parse(substr($xs, 2));
132+
return [new Lam($t), $xs];
133+
} elseif ($xs[0] == '0' && $xs[1] == '1') {
134+
list($l, $xs) = parse(substr($xs, 2));
135+
list($r, $xss) = parse($xs);
136+
return [new App($l, $r), $xss];
137+
} elseif ($xs[0] == '1') {
138+
list($os, $xs) = span(function ($x) { return $x == '1'; }, $xs);
139+
return [new BVar(strlen($os)), '0'.$xs];
140+
} else {
141+
throw new \Exception("Invalid expression");
142+
}
143+
}
144+
145+
function whnf($e, $env)
146+
{
147+
if ($e instanceof BVar) {
148+
$term = $env[$e->i-1];
149+
if ($term instanceof Idx) {
150+
return new BReturn($term);
151+
}
152+
elseif ($term instanceof TE) {
153+
return whnf($term->term, $term->env);
154+
}
155+
} elseif ($e instanceof Lam) {
156+
return new BReturn(new TE($e, $env));
157+
} elseif ($e instanceof App) {
158+
$l = $e->e1;
159+
$r = $e->e2;
160+
161+
$wl = whnf($l, $env);
162+
if ($wl instanceof BReturn &&
163+
$wl->cls instanceof TE &&
164+
$wl->cls->term instanceof Lam) {
165+
166+
$le = $wl->cls->term->e;
167+
$env_ = $wl->cls->env;
168+
return whnf($le, array_merge([new TE($r, $env)], $env_));
169+
} else {
170+
return new Apply($wl, $r, $env);
171+
}
172+
} else {
173+
assert(0);
174+
}
175+
}
176+
177+
function _nf($d, $t)
178+
{
179+
if ($t instanceof Apply) {
180+
return new App(_nf($d, $t->e1), nf($d, $t->e2, $t->env));
181+
} elseif ($t instanceof BReturn) {
182+
if ($t->cls instanceof TE && $t->cls->term instanceof Lam) {
183+
return new Lam(nf(($d+1), $t->cls->term->e, array_merge([new Idx($d)], $t->cls->env)));
184+
} elseif ($t->cls instanceof TE) {
185+
return $t->cls->term;
186+
} elseif ($t->cls instanceof Idx) {
187+
return new BVar($d - $t->cls->i - 1);
188+
} else {
189+
assert(0);
190+
}
191+
} else {
192+
assert(0);
193+
}
194+
}
195+
196+
function nf($d, $t, $env)
197+
{
198+
return _nf($d, whnf($t, $env));
199+
}
200+
201+
$prg1 = '0010';
202+
$prg2 = '0000000101101110110';
203+
$prg3 = '00010001100110010100011010000000010110000010010001010111110111101001000110100001110011010000000000101101110011100111111101111000000001111100110111000000101100000110110';
204+
$eval = '0101000110100000000101011000000000011110000101111110011110000101110011110000001111000010110110111001111100001111100001011110100111010010110011100001101100001011111000011111000011100110111101111100111101110110000110010001101000011010';
205+
206+
$p1 = parse($prg1)[0];
207+
$p2 = parse($prg2)[0];
208+
$p3 = parse($prg3)[0];
209+
$pe = parse($eval)[0];
210+
211+
var_dump($p1);
212+
213+
echo (string) $p2."\n";
214+
echo (string) nf(0, $p2, [])."\n";

0 commit comments

Comments
 (0)