-
Notifications
You must be signed in to change notification settings - Fork 0
/
compute.js
59 lines (52 loc) · 1.48 KB
/
compute.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
const omitAttr = attr => obj => {
const { [attr]: omit, ...rest }= obj;
return rest;
}
const fnToName = defs => fn => {
//TODO recognize λx.x and λy.y as the same for example
const named = Object.keys(defs)
.map(name => ({
name, str: compute(defs[name].func, {}, omitAttr(name)(defs))
}))
.find(f => f.str == fn ); // IMPROVEME
return (named && named.name) || fn
}
const lookupdefs = defs => name =>
defs[name] && defs[name].func
const application = (ast, vars = {}, defs = {}) => {
switch(ast.func.type) {
case "function":
return compute(ast.func.body, {...vars, [ast.func.arg]: ast.arg }, defs)
case "app":
return compute(ast.func, vars, defs)
case "var":
return application(
{...ast, func: lookupdefs(defs)(ast.func.name) || ast.func },
{...vars, [ast.func.arg]: ast.arg },
defs
)
default:
return `(${compute(ast.func, vars, defs)} ${compute(ast.arg, vars, defs)})`
}
}
const compute = (ast, vars = {}, defs = {}) => {
switch(ast.type) {
case "withdefs":
return compute(ast.exp, vars, ast.defs)
case "app":
return application(ast, vars, defs)
case "function":
return fnToName(defs)(
`λ${ast.arg}.${compute(ast.body, vars, defs)}`
)
case "var":
return compute(
lookupdefs(defs)(ast.name) || vars[ast.name] || ast.name,
omitAttr(ast.name)(vars),
defs
)
default:
return ast
}
}
module.exports = compute;