Skip to content

Commit

Permalink
add terms.combinators
Browse files Browse the repository at this point in the history
  • Loading branch information
Deric-W committed Sep 9, 2022
1 parent 1bc5ddc commit b2d85d4
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 3 deletions.
2 changes: 1 addition & 1 deletion lambda_calculus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from .terms import Variable, Abstraction, Application

__version__ = "2.1.0"
__version__ = "2.2.0"
__author__ = "Eric Niklas Wolf"
__email__ = "[email protected]"
__all__ = (
Expand Down
3 changes: 2 additions & 1 deletion lambda_calculus/terms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"Application",
"arithmetic",
"logic",
"pairs"
"pairs",
"combinators"
)

T = TypeVar("T")
Expand Down
55 changes: 55 additions & 0 deletions lambda_calculus/terms/combinators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/python3

"""Common combinators"""

from . import Variable, Application

__all__ = (
"Y",
"S",
"K",
"I",
"B",
"C",
"W",
"DELTA",
"OMEGA"
)

Y = Application(
Variable("g").apply_to(
Variable("x").apply_to(Variable("x"))
).abstract("x"),
Variable("g").apply_to(
Variable("x").apply_to(Variable("x"))
).abstract("x")
).abstract("g")

S = Variable("x").apply_to(
Variable("z"),
Variable("y").apply_to(Variable("z"))
).abstract("x", "y", "z")

K = Variable("x").abstract("x", "y")

I = Variable("x").abstract("x")

B = Variable("x").apply_to(
Variable("y").apply_to(Variable("z"))
).abstract("x", "y", "z")

C = Variable("x").apply_to(
Variable("z"),
Variable("y")
).abstract("x", "y", "z")

W = Variable("x").apply_to(
Variable("y"),
Variable("y")
).abstract("x", "y")

DELTA = Variable("x").apply_to(
Variable("x")
).abstract("x")

OMEGA = DELTA.apply_to(DELTA)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "lambda_calculus"
version = "2.1.0"
version = "2.2.0"
description = "Implementation of the Lambda calculus"
requires-python = ">=3.10"
keywords = []
Expand Down
96 changes: 96 additions & 0 deletions tests/terms/test_combinators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/python3

"""Tests for combinator terms"""

from unittest import TestCase
from lambda_calculus.terms import Variable, combinators
from lambda_calculus.visitors.normalisation import BetaNormalisingVisitor


class CombinatorTest(TestCase):
"""Tests for combinator terms"""

def test_is_combinator(self) -> None:
"""test that all terms a combinators"""
for name in combinators.__all__:
self.assertTrue(getattr(combinators, name).is_combinator())

def test_y(self) -> None:
"""test Y combinator"""
self.assertEqual(
BetaNormalisingVisitor().skip_intermediate(
combinators.Y.apply_to(combinators.K.apply_to(Variable("a")))
),
Variable("a")
)

def test_s(self) -> None:
"""test S combinator"""
term = Variable("a")
self.assertEqual(
BetaNormalisingVisitor().skip_intermediate(
combinators.S.apply_to(combinators.K, Variable("b"), term)
),
term
)

def test_k(self) -> None:
"""test K combinator"""
term = Variable("a")
self.assertEqual(
BetaNormalisingVisitor().skip_intermediate(
combinators.K.apply_to(term, Variable("b"))
),
term
)

def test_i(self) -> None:
"""test I combinator"""
term = Variable("a")
self.assertEqual(
BetaNormalisingVisitor().skip_intermediate(
combinators.I.apply_to(term)
),
term
)

def test_b(self) -> None:
"""test B combinator"""
self.assertEqual(
BetaNormalisingVisitor().skip_intermediate(
combinators.B.apply_to(
combinators.K.apply_to(Variable("b")),
combinators.K.apply_to(Variable("c")),
Variable("a")
)
),
Variable("b")
)

def test_c(self) -> None:
"""test C combinator"""
self.assertEqual(
BetaNormalisingVisitor().skip_intermediate(
combinators.C.apply_to(combinators.I, Variable("a"), Variable("b"))
),
Variable("b").apply_to(Variable("a"))
)

def test_w(self) -> None:
"""test W combinator"""
self.assertEqual(
BetaNormalisingVisitor().skip_intermediate(
combinators.W.apply_to(combinators.I, Variable("a"))
),
Variable("a").apply_to(Variable("a"))
)

def test_omega(self) -> None:
"""test Omega combinator"""
for index, (_, step) in enumerate(BetaNormalisingVisitor().visit(combinators.OMEGA)):
if index < 10:
self.assertEqual(step, combinators.OMEGA)
else:
break
else:
self.fail("reached beta normal form")

0 comments on commit b2d85d4

Please sign in to comment.