Skip to content

Commit b2d85d4

Browse files
committed
add terms.combinators
1 parent 1bc5ddc commit b2d85d4

File tree

5 files changed

+155
-3
lines changed

5 files changed

+155
-3
lines changed

lambda_calculus/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from .terms import Variable, Abstraction, Application
66

7-
__version__ = "2.1.0"
7+
__version__ = "2.2.0"
88
__author__ = "Eric Niklas Wolf"
99
__email__ = "[email protected]"
1010
__all__ = (

lambda_calculus/terms/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"Application",
2020
"arithmetic",
2121
"logic",
22-
"pairs"
22+
"pairs",
23+
"combinators"
2324
)
2425

2526
T = TypeVar("T")
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/python3
2+
3+
"""Common combinators"""
4+
5+
from . import Variable, Application
6+
7+
__all__ = (
8+
"Y",
9+
"S",
10+
"K",
11+
"I",
12+
"B",
13+
"C",
14+
"W",
15+
"DELTA",
16+
"OMEGA"
17+
)
18+
19+
Y = Application(
20+
Variable("g").apply_to(
21+
Variable("x").apply_to(Variable("x"))
22+
).abstract("x"),
23+
Variable("g").apply_to(
24+
Variable("x").apply_to(Variable("x"))
25+
).abstract("x")
26+
).abstract("g")
27+
28+
S = Variable("x").apply_to(
29+
Variable("z"),
30+
Variable("y").apply_to(Variable("z"))
31+
).abstract("x", "y", "z")
32+
33+
K = Variable("x").abstract("x", "y")
34+
35+
I = Variable("x").abstract("x")
36+
37+
B = Variable("x").apply_to(
38+
Variable("y").apply_to(Variable("z"))
39+
).abstract("x", "y", "z")
40+
41+
C = Variable("x").apply_to(
42+
Variable("z"),
43+
Variable("y")
44+
).abstract("x", "y", "z")
45+
46+
W = Variable("x").apply_to(
47+
Variable("y"),
48+
Variable("y")
49+
).abstract("x", "y")
50+
51+
DELTA = Variable("x").apply_to(
52+
Variable("x")
53+
).abstract("x")
54+
55+
OMEGA = DELTA.apply_to(DELTA)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "lambda_calculus"
3-
version = "2.1.0"
3+
version = "2.2.0"
44
description = "Implementation of the Lambda calculus"
55
requires-python = ">=3.10"
66
keywords = []

tests/terms/test_combinators.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/python3
2+
3+
"""Tests for combinator terms"""
4+
5+
from unittest import TestCase
6+
from lambda_calculus.terms import Variable, combinators
7+
from lambda_calculus.visitors.normalisation import BetaNormalisingVisitor
8+
9+
10+
class CombinatorTest(TestCase):
11+
"""Tests for combinator terms"""
12+
13+
def test_is_combinator(self) -> None:
14+
"""test that all terms a combinators"""
15+
for name in combinators.__all__:
16+
self.assertTrue(getattr(combinators, name).is_combinator())
17+
18+
def test_y(self) -> None:
19+
"""test Y combinator"""
20+
self.assertEqual(
21+
BetaNormalisingVisitor().skip_intermediate(
22+
combinators.Y.apply_to(combinators.K.apply_to(Variable("a")))
23+
),
24+
Variable("a")
25+
)
26+
27+
def test_s(self) -> None:
28+
"""test S combinator"""
29+
term = Variable("a")
30+
self.assertEqual(
31+
BetaNormalisingVisitor().skip_intermediate(
32+
combinators.S.apply_to(combinators.K, Variable("b"), term)
33+
),
34+
term
35+
)
36+
37+
def test_k(self) -> None:
38+
"""test K combinator"""
39+
term = Variable("a")
40+
self.assertEqual(
41+
BetaNormalisingVisitor().skip_intermediate(
42+
combinators.K.apply_to(term, Variable("b"))
43+
),
44+
term
45+
)
46+
47+
def test_i(self) -> None:
48+
"""test I combinator"""
49+
term = Variable("a")
50+
self.assertEqual(
51+
BetaNormalisingVisitor().skip_intermediate(
52+
combinators.I.apply_to(term)
53+
),
54+
term
55+
)
56+
57+
def test_b(self) -> None:
58+
"""test B combinator"""
59+
self.assertEqual(
60+
BetaNormalisingVisitor().skip_intermediate(
61+
combinators.B.apply_to(
62+
combinators.K.apply_to(Variable("b")),
63+
combinators.K.apply_to(Variable("c")),
64+
Variable("a")
65+
)
66+
),
67+
Variable("b")
68+
)
69+
70+
def test_c(self) -> None:
71+
"""test C combinator"""
72+
self.assertEqual(
73+
BetaNormalisingVisitor().skip_intermediate(
74+
combinators.C.apply_to(combinators.I, Variable("a"), Variable("b"))
75+
),
76+
Variable("b").apply_to(Variable("a"))
77+
)
78+
79+
def test_w(self) -> None:
80+
"""test W combinator"""
81+
self.assertEqual(
82+
BetaNormalisingVisitor().skip_intermediate(
83+
combinators.W.apply_to(combinators.I, Variable("a"))
84+
),
85+
Variable("a").apply_to(Variable("a"))
86+
)
87+
88+
def test_omega(self) -> None:
89+
"""test Omega combinator"""
90+
for index, (_, step) in enumerate(BetaNormalisingVisitor().visit(combinators.OMEGA)):
91+
if index < 10:
92+
self.assertEqual(step, combinators.OMEGA)
93+
else:
94+
break
95+
else:
96+
self.fail("reached beta normal form")

0 commit comments

Comments
 (0)