-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathlambda_.py
More file actions
151 lines (119 loc) · 3.38 KB
/
Copy pathlambda_.py
File metadata and controls
151 lines (119 loc) · 3.38 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import functools
from typing import Annotated, Callable
from effectful.ops.semantics import coproduct, evaluate, fvsof, fwd, handler
from effectful.ops.syntax import Scoped, defdata, defop, syntactic_eq
from effectful.ops.types import Expr, Interpretation, NotHandled, Operation, Term
add = defdata.dispatch(int).__add__
@defop
def App[S, T](f: Callable[[S], T], arg: S) -> T:
raise NotHandled
@defop
def Lam[S, T, A](
var: Annotated[Operation[[], S], Scoped[A]], body: Annotated[T, Scoped[A]]
) -> Callable[[S], T]:
raise NotHandled
@defop
def Let[S, T, A](
var: Annotated[Operation[[], S], Scoped[A]],
val: S,
body: Annotated[T, Scoped[A]],
) -> T:
raise NotHandled
def beta_add(x: Expr[int], y: Expr[int]) -> Expr[int]:
"""integer addition"""
match x, y:
case int(), int():
return x + y
case _:
return fwd()
def beta_app[S, T](f: Expr[Callable[[S], T]], arg: Expr[S]) -> Expr[T]:
"""beta reduction"""
match f, arg:
case Term(op, (var, body)), _ if op == Lam:
return handler({var: lambda: arg})(evaluate)(body)
case _:
return fwd()
def beta_let[S, T](var: Operation[[], S], val: Expr[S], body: Expr[T]) -> Expr[T]:
"""let binding"""
return handler({var: lambda: val})(evaluate)(body)
def eta_lam[S, T](
var: Operation[[], S], body: Expr[T]
) -> Expr[Callable[[S], T]] | Expr[T]:
"""eta reduction"""
if var not in fvsof(body):
return body
else:
return fwd()
def eta_let[S, T](var: Operation[[], S], val: Expr[S], body: Expr[T]) -> Expr[T]:
"""eta reduction"""
if var not in fvsof(body):
return body
else:
return fwd()
def commute_add(x: Expr[int], y: Expr[int]) -> Expr[int]:
match x, y:
case Term(), int():
return y + x # type: ignore
case _:
return fwd()
def assoc_add(x: Expr[int], y: Expr[int]) -> Expr[int]:
match x, y:
case _, Term(op, (a, b)) if op == add:
return (x + a) + b # type: ignore
case _:
return fwd()
def unit_add(x: Expr[int], y: Expr[int]) -> Expr[int]:
if syntactic_eq(y, 0):
return x
elif syntactic_eq(x, 0):
return y
else:
return fwd()
def sort_add(x: Expr[int], y: Expr[int]) -> Expr[int]:
match x, y:
case Term(vx, ()), Term(vy, ()) if id(vx) > id(vy):
return y + x # type: ignore
case Term(add_, (a, Term(vx, ()))), Term(vy, ()) if add_ == add and id(vx) > id(
vy
):
return (a + vy()) + vx()
case _:
return fwd()
eta_rules: Interpretation = {
Lam: eta_lam,
Let: eta_let,
}
beta_rules: Interpretation = {
add: beta_add,
App: beta_app,
Let: beta_let,
}
commute_rules: Interpretation = {
add: commute_add,
}
assoc_rules: Interpretation = {
add: assoc_add,
}
unit_rules: Interpretation = {
add: unit_add,
}
sort_rules: Interpretation = {
add: sort_add,
}
eager_mixed = functools.reduce(
coproduct,
(
eta_rules,
beta_rules,
commute_rules,
assoc_rules,
unit_rules,
sort_rules,
),
)
if __name__ == "__main__":
x, y = defop(int, name="x"), defop(int, name="y")
with handler(eager_mixed):
f2 = Lam(x, Lam(y, (x() + y())))
assert App(App(f2, 1), 2) == 3
assert Lam(y, f2) == f2