Skip to content

Commit bb854f6

Browse files
authored
Remove non-uniform behavior for numeric equality (#306)
* remove non-uniform behavior for eq * lint * fix some tests * remove breakpoint
1 parent ec7b64d commit bb854f6

3 files changed

Lines changed: 50 additions & 52 deletions

File tree

docs/source/lambda_.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from effectful.handlers.numbers import add
55
from effectful.ops.semantics import coproduct, evaluate, fvsof, fwd, handler
6-
from effectful.ops.syntax import Scoped, defop
6+
from effectful.ops.syntax import Scoped, defop, syntactic_eq
77
from effectful.ops.types import Expr, Interpretation, Operation, Term
88

99

@@ -84,13 +84,12 @@ def assoc_add(x: Expr[int], y: Expr[int]) -> Expr[int]:
8484

8585

8686
def unit_add(x: Expr[int], y: Expr[int]) -> Expr[int]:
87-
match x, y:
88-
case _, 0:
89-
return x
90-
case 0, _:
91-
return y
92-
case _:
93-
return fwd()
87+
if syntactic_eq(y, 0):
88+
return x
89+
elif syntactic_eq(x, 0):
90+
return y
91+
else:
92+
return fwd()
9493

9594

9695
def sort_add(x: Expr[int], y: Expr[int]) -> Expr[int]:

effectful/handlers/numbers.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import operator
77
from typing import Any
88

9-
from effectful.ops.syntax import defdata, defop, syntactic_eq
9+
from effectful.ops.syntax import defdata, defop
1010
from effectful.ops.types import Expr, Operation, Term
1111

1212

@@ -37,14 +37,6 @@ def __hash__(self):
3737

3838

3939
# Complex specific methods
40-
@defop
41-
def eq[T_Number: numbers.Number](x: T_Number, y: T_Number) -> bool:
42-
if not any(isinstance(a, Term) for a in (x, y)):
43-
return operator.eq(x, y)
44-
else:
45-
return syntactic_eq(x, y)
46-
47-
4840
def _wrap_cmp(op):
4941
def _wrapped_op[T_Number: numbers.Number](x: T_Number, y: T_Number) -> bool:
5042
if not any(isinstance(a, Term) for a in (x, y)):
@@ -86,6 +78,7 @@ def _wrapped_op[T_Number: numbers.Number](x: T_Number) -> T_Number:
8678
truediv = defop(_wrap_binop(operator.truediv))
8779
pow = defop(_wrap_binop(operator.pow))
8880
abs = defop(_wrap_unop(operator.abs))
81+
eq = defop(_wrap_cmp(operator.eq))
8982

9083

9184
@defdata.register(numbers.Complex)

tests/test_handlers_numbers.py

Lines changed: 41 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from docs.source.lambda_ import App, Lam, Let, eager_mixed
88
from effectful.ops.semantics import evaluate, fvsof, handler, typeof
9-
from effectful.ops.syntax import defop, trace
9+
from effectful.ops.syntax import defop, syntactic_eq, trace
1010
from effectful.ops.types import Term
1111

1212
logger = logging.getLogger(__name__)
@@ -19,9 +19,9 @@ def test_lambda_calculus_1():
1919
e1 = x() + 1
2020
f1 = Lam(x, e1)
2121

22-
assert App(f1, 1) == 2
23-
assert Lam(y, f1) == f1
24-
assert Lam(x, f1.args[1]) == f1.args[1]
22+
assert syntactic_eq(App(f1, 1), 2)
23+
assert syntactic_eq(Lam(y, f1), f1)
24+
assert syntactic_eq(Lam(x, f1.args[1]), f1.args[1])
2525

2626
assert fvsof(e1) == fvsof(x() + 1)
2727
assert fvsof(Lam(x, e1).args[1]) != fvsof(Lam(x, e1).args[1])
@@ -35,8 +35,8 @@ def test_lambda_calculus_2():
3535

3636
with handler(eager_mixed):
3737
f2 = Lam(x, Lam(y, (x() + y())))
38-
assert App(App(f2, 1), 2) == 3
39-
assert Lam(y, f2) == f2
38+
assert syntactic_eq(App(App(f2, 1), 2), 3)
39+
assert syntactic_eq(Lam(y, f2), f2)
4040

4141

4242
def test_lambda_calculus_3():
@@ -45,7 +45,7 @@ def test_lambda_calculus_3():
4545
with handler(eager_mixed):
4646
f2 = Lam(x, Lam(y, (x() + y())))
4747
app2 = Lam(f, Lam(x, Lam(y, App(App(f(), x()), y()))))
48-
assert App(App(App(app2, f2), 1), 2) == 3
48+
assert syntactic_eq(App(App(App(app2, f2), 1), 2), 3)
4949

5050

5151
def test_lambda_calculus_4():
@@ -59,7 +59,7 @@ def test_lambda_calculus_4():
5959
add1 = Lam(x, (x() + 1))
6060
compose = Lam(f, Lam(g, Lam(x, App(f(), App(g(), x())))))
6161
f1_twice = App(App(compose, add1), add1)
62-
assert App(f1_twice, 1) == 3
62+
assert syntactic_eq(App(f1_twice, 1), 3)
6363

6464

6565
def test_lambda_calculus_5():
@@ -75,63 +75,65 @@ def test_lambda_calculus_5():
7575
assert x not in fvsof(f_add1)
7676
assert f_add1.args[0] != f_add1.args[1].args[0]
7777

78-
assert App(f_add1, 1) == 2
79-
assert Let(x, 1, e_add1) == 2
78+
assert syntactic_eq(App(f_add1, 1), 2)
79+
assert syntactic_eq(Let(x, 1, e_add1), 2)
8080

8181

8282
def test_arithmetic_1():
8383
x_, y_ = defop(int), defop(int)
8484
x, y = x_(), y_()
8585

8686
with handler(eager_mixed):
87-
assert (1 + 2) + x == x + 3
88-
assert not (x + 1 == y + 1)
89-
assert x + 0 == 0 + x == x
87+
assert syntactic_eq((1 + 2) + x, x + 3)
88+
assert not syntactic_eq(x + 1, y + 1)
89+
assert syntactic_eq(x + 0, 0 + x) and syntactic_eq(0 + x, x)
9090

9191

9292
def test_arithmetic_2():
9393
x_, y_ = defop(int), defop(int)
9494
x, y = x_(), y_()
9595

9696
with handler(eager_mixed):
97-
assert x + y == y + x
98-
assert 3 + x == x + 3
99-
assert 1 + (x + 2) == x + 3
100-
assert (x + 1) + 2 == x + 3
97+
assert syntactic_eq(x + y, y + x)
98+
assert syntactic_eq(3 + x, x + 3)
99+
assert syntactic_eq(1 + (x + 2), x + 3)
100+
assert syntactic_eq((x + 1) + 2, x + 3)
101101

102102

103103
def test_arithmetic_3():
104104
x_, y_ = defop(int), defop(int)
105105
x, y = x_(), y_()
106106

107107
with handler(eager_mixed):
108-
assert (1 + (y + 1)) + (1 + (x + 1)) == (y + x) + 4
109-
assert 1 + ((x + y) + 2) == (x + y) + 3
110-
assert 1 + ((x + (y + 1)) + 1) == (x + y) + 3
108+
assert syntactic_eq((1 + (y + 1)) + (1 + (x + 1)), (y + x) + 4)
109+
assert syntactic_eq(1 + ((x + y) + 2), (x + y) + 3)
110+
assert syntactic_eq(1 + ((x + (y + 1)) + 1), (x + y) + 3)
111111

112112

113113
def test_arithmetic_4():
114114
x_, y_ = defop(int), defop(int)
115115
x, y = x_(), y_()
116116

117117
with handler(eager_mixed):
118-
assert (
119-
((x + x) + (x + x)) + ((x + x) + (x + x))
120-
== x + (x + (x + (x + (x + (x + (x + x))))))
121-
== ((((((x + x) + x) + x) + x) + x) + x) + x
122-
)
118+
expr1 = ((x + x) + (x + x)) + ((x + x) + (x + x))
119+
expr2 = x + (x + (x + (x + (x + (x + (x + x))))))
120+
expr3 = ((((((x + x) + x) + x) + x) + x) + x) + x
121+
assert syntactic_eq(expr1, expr2) and syntactic_eq(expr2, expr3)
123122

124-
assert (x + y) + (y + x) == (y + (x + x)) + y == y + (x + (y + x))
123+
expr4 = (x + y) + (y + x)
124+
expr5 = (y + (x + x)) + y
125+
expr6 = y + (x + (y + x))
126+
assert syntactic_eq(expr4, expr5) and syntactic_eq(expr5, expr6)
125127

126128

127129
def test_arithmetic_5():
128130
x, y = defop(int), defop(int)
129131

130132
with handler(eager_mixed):
131-
assert Let(x, x() + 3, x() + 1) == x() + 4
132-
assert Let(x, x() + 3, x() + y() + 1) == y() + x() + 4
133+
assert syntactic_eq(Let(x, x() + 3, x() + 1), x() + 4)
134+
assert syntactic_eq(Let(x, x() + 3, x() + y() + 1), y() + x() + 4)
133135

134-
assert Let(x, x() + 3, Let(x, x() + 4, x() + y())) == x() + y() + 7
136+
assert syntactic_eq(Let(x, x() + 3, Let(x, x() + 4, x() + y())), x() + y() + 7)
135137

136138

137139
def test_defun_1():
@@ -147,8 +149,8 @@ def f1(x: int) -> int:
147149
assert y in fvsof(f1)
148150
assert x not in fvsof(f1)
149151

150-
assert f1(1) == y() + 2
151-
assert f1(x()) == x() + y() + 1
152+
assert syntactic_eq(f1(1), y() + 2)
153+
assert syntactic_eq(f1(x()), x() + y() + 1)
152154

153155

154156
def test_defun_2():
@@ -166,7 +168,7 @@ def f2_inner(y: int) -> int:
166168

167169
return f2_inner(y)
168170

169-
assert f1(1, 2) == f2(1, 2) == 3
171+
assert syntactic_eq(f1(1, 2), 3) and syntactic_eq(f2(1, 2), 3)
170172

171173

172174
def test_defun_3():
@@ -180,7 +182,7 @@ def f2(x: int, y: int) -> int:
180182
def app2(f: collections.abc.Callable, x: int, y: int) -> int:
181183
return f(x, y)
182184

183-
assert app2(f2, 1, 2) == 3
185+
assert syntactic_eq(app2(f2, 1, 2), 3)
184186

185187

186188
@pytest.mark.xfail(condition=os.getenv("CI") == "true", reason="Fails on CI")
@@ -216,8 +218,12 @@ def add1_twice(x: int) -> int:
216218

217219
assert callable(add1_twice), f"add1_twice is not callable: {add1_twice}"
218220

219-
assert add1_twice(1) == compose(add1, add1)(1) == 3
220-
assert add1_twice(x()) == compose(add1, add1)(x()) == x() + 2
221+
assert syntactic_eq(add1_twice(1), 3) and syntactic_eq(
222+
compose(add1, add1)(1), 3
223+
)
224+
assert syntactic_eq(add1_twice(x()), x() + 2) and syntactic_eq(
225+
compose(add1, add1)(x()), x() + 2
226+
)
221227

222228

223229
def test_defun_5():

0 commit comments

Comments
 (0)