lambda-calculus 3.0.0__py3-none-any.whl → 3.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lambda_calculus/__init__.py +5 -14
- lambda_calculus/_version.py +24 -0
- lambda_calculus/errors.py +3 -6
- lambda_calculus/terms/__init__.py +56 -50
- lambda_calculus/terms/abc.py +17 -0
- lambda_calculus/terms/arithmetic.py +17 -63
- lambda_calculus/terms/combinators.py +15 -39
- lambda_calculus/terms/logic.py +7 -18
- lambda_calculus/terms/pairs.py +7 -27
- lambda_calculus/visitors/__init__.py +24 -23
- lambda_calculus/visitors/normalisation.py +21 -19
- lambda_calculus/visitors/substitution/__init__.py +20 -23
- lambda_calculus/visitors/substitution/checked.py +13 -23
- lambda_calculus/visitors/substitution/renaming.py +42 -36
- lambda_calculus/visitors/substitution/unsafe.py +12 -13
- lambda_calculus/visitors/walking.py +5 -9
- {lambda_calculus-3.0.0.dist-info → lambda_calculus-3.1.1.dist-info}/METADATA +9 -8
- lambda_calculus-3.1.1.dist-info/RECORD +21 -0
- {lambda_calculus-3.0.0.dist-info → lambda_calculus-3.1.1.dist-info}/WHEEL +1 -2
- lambda_calculus-3.0.0.dist-info/RECORD +0 -20
- lambda_calculus-3.0.0.dist-info/top_level.txt +0 -1
- {lambda_calculus-3.0.0.dist-info → lambda_calculus-3.1.1.dist-info/licenses}/LICENSE +0 -0
lambda_calculus/__init__.py
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
|
-
|
|
3
1
|
"""Implementation of the Lambda calculus"""
|
|
4
2
|
|
|
5
|
-
from .
|
|
3
|
+
from ._version import version as __version__ # noqa: F401
|
|
4
|
+
from .terms import Abstraction, Application, Variable
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
__all__ = (
|
|
11
|
-
"Variable",
|
|
12
|
-
"Abstraction",
|
|
13
|
-
"Application",
|
|
14
|
-
"terms",
|
|
15
|
-
"visitors",
|
|
16
|
-
"errors"
|
|
17
|
-
)
|
|
6
|
+
__author__ = "Eric Niklas Wolf"
|
|
7
|
+
__email__ = "eric_niklas.wolf@mailbox.tu-dresden.de"
|
|
8
|
+
__all__ = ("Abstraction", "Application", "Variable", "errors", "terms", "visitors")
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '3.1.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (3, 1, 1)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
lambda_calculus/errors.py
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
|
-
|
|
3
1
|
"""Errors raised by Term operations"""
|
|
4
2
|
|
|
5
3
|
from __future__ import annotations
|
|
4
|
+
|
|
6
5
|
from collections.abc import Collection
|
|
7
|
-
from typing import
|
|
6
|
+
from typing import Generic, TypeVar
|
|
8
7
|
|
|
9
|
-
__all__ = (
|
|
10
|
-
"CollisionError",
|
|
11
|
-
)
|
|
8
|
+
__all__ = ("CollisionError",)
|
|
12
9
|
|
|
13
10
|
V = TypeVar("V")
|
|
14
11
|
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
|
-
|
|
3
1
|
"""Lambda Terms"""
|
|
4
2
|
|
|
5
3
|
from __future__ import annotations
|
|
4
|
+
|
|
6
5
|
from abc import abstractmethod
|
|
7
|
-
from collections.abc import
|
|
6
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
7
|
+
from collections.abc import Set as AbstractSet
|
|
8
8
|
from dataclasses import dataclass
|
|
9
|
-
from typing import TypeVar, final
|
|
10
|
-
|
|
9
|
+
from typing import Self, TypeVar, final
|
|
10
|
+
|
|
11
11
|
from ..errors import CollisionError
|
|
12
|
-
from ..visitors import walking
|
|
12
|
+
from ..visitors import Visitor, walking
|
|
13
13
|
from ..visitors.substitution import checked
|
|
14
14
|
|
|
15
15
|
__all__ = (
|
|
16
|
-
"Term",
|
|
17
|
-
"Variable",
|
|
18
16
|
"Abstraction",
|
|
19
17
|
"Application",
|
|
18
|
+
"Term",
|
|
19
|
+
"Variable",
|
|
20
|
+
"abc",
|
|
20
21
|
"arithmetic",
|
|
22
|
+
"combinators",
|
|
21
23
|
"logic",
|
|
22
24
|
"pairs",
|
|
23
|
-
"combinators"
|
|
24
25
|
)
|
|
25
26
|
|
|
26
27
|
T = TypeVar("T")
|
|
@@ -51,25 +52,25 @@ class Term(Iterable["Term[V]"]):
|
|
|
51
52
|
|
|
52
53
|
:return: lambda term string
|
|
53
54
|
"""
|
|
54
|
-
raise NotImplementedError
|
|
55
|
+
raise NotImplementedError
|
|
55
56
|
|
|
56
57
|
@abstractmethod
|
|
57
|
-
def free_variables(self) ->
|
|
58
|
+
def free_variables(self) -> AbstractSet[V]:
|
|
58
59
|
"""
|
|
59
60
|
Calculate the free variables of this Term.
|
|
60
61
|
|
|
61
62
|
:return: variables not bound by an abstraction
|
|
62
63
|
"""
|
|
63
|
-
raise NotImplementedError
|
|
64
|
+
raise NotImplementedError
|
|
64
65
|
|
|
65
66
|
@abstractmethod
|
|
66
|
-
def bound_variables(self) ->
|
|
67
|
+
def bound_variables(self) -> AbstractSet[V]:
|
|
67
68
|
"""
|
|
68
69
|
Calculate the bound variables of this Term.
|
|
69
70
|
|
|
70
71
|
:return: variables bound by an abstraction
|
|
71
72
|
"""
|
|
72
|
-
raise NotImplementedError
|
|
73
|
+
raise NotImplementedError
|
|
73
74
|
|
|
74
75
|
@abstractmethod
|
|
75
76
|
def is_beta_normal_form(self) -> bool:
|
|
@@ -78,17 +79,17 @@ class Term(Iterable["Term[V]"]):
|
|
|
78
79
|
|
|
79
80
|
:return: if no beta reductions can be performed
|
|
80
81
|
"""
|
|
81
|
-
raise NotImplementedError
|
|
82
|
+
raise NotImplementedError
|
|
82
83
|
|
|
83
84
|
@abstractmethod
|
|
84
|
-
def accept(self, visitor:
|
|
85
|
+
def accept(self, visitor: Visitor[T, V]) -> T:
|
|
85
86
|
"""
|
|
86
87
|
Accept a visitor by calling his corresponding method.
|
|
87
88
|
|
|
88
89
|
:param visitor: Visitor to accept
|
|
89
90
|
:return: value returned by the visitors corresponding method
|
|
90
91
|
"""
|
|
91
|
-
raise NotImplementedError
|
|
92
|
+
raise NotImplementedError
|
|
92
93
|
|
|
93
94
|
def abstract(self, *variables: V) -> Abstraction[V]:
|
|
94
95
|
"""
|
|
@@ -140,7 +141,7 @@ class Variable(Term[V]):
|
|
|
140
141
|
name: V
|
|
141
142
|
|
|
142
143
|
@classmethod
|
|
143
|
-
def with_valid_name(cls, name: V) ->
|
|
144
|
+
def with_valid_name(cls, name: V) -> Self:
|
|
144
145
|
"""
|
|
145
146
|
Create an instance with a valid name.
|
|
146
147
|
|
|
@@ -150,10 +151,12 @@ class Variable(Term[V]):
|
|
|
150
151
|
"""
|
|
151
152
|
string = str(name)
|
|
152
153
|
if not string:
|
|
153
|
-
|
|
154
|
+
msg = "empty string representation"
|
|
155
|
+
raise ValueError(msg)
|
|
154
156
|
for character in string:
|
|
155
157
|
if character in "().λ" or character.isspace():
|
|
156
|
-
|
|
158
|
+
msg = f"invalid character: '{character}'"
|
|
159
|
+
raise ValueError(msg)
|
|
157
160
|
return cls(name)
|
|
158
161
|
|
|
159
162
|
def __str__(self) -> str:
|
|
@@ -164,7 +167,7 @@ class Variable(Term[V]):
|
|
|
164
167
|
"""
|
|
165
168
|
return str(self.name)
|
|
166
169
|
|
|
167
|
-
def free_variables(self) ->
|
|
170
|
+
def free_variables(self) -> AbstractSet[V]:
|
|
168
171
|
"""
|
|
169
172
|
Calculate the free variables of this Term.
|
|
170
173
|
|
|
@@ -172,7 +175,7 @@ class Variable(Term[V]):
|
|
|
172
175
|
"""
|
|
173
176
|
return {self.name}
|
|
174
177
|
|
|
175
|
-
def bound_variables(self) ->
|
|
178
|
+
def bound_variables(self) -> AbstractSet[V]:
|
|
176
179
|
"""
|
|
177
180
|
Calculate the bound variables of this Term.
|
|
178
181
|
|
|
@@ -188,7 +191,7 @@ class Variable(Term[V]):
|
|
|
188
191
|
"""
|
|
189
192
|
return True
|
|
190
193
|
|
|
191
|
-
def accept(self, visitor:
|
|
194
|
+
def accept(self, visitor: Visitor[T, V]) -> T:
|
|
192
195
|
"""
|
|
193
196
|
Accept a visitor by calling visitors.Visitor.visit_variable.
|
|
194
197
|
|
|
@@ -213,7 +216,7 @@ class Abstraction(Term[V]):
|
|
|
213
216
|
body: Term[V]
|
|
214
217
|
|
|
215
218
|
@classmethod
|
|
216
|
-
def curried(cls, variables: Sequence[V], body: Term[V]) ->
|
|
219
|
+
def curried(cls, variables: Sequence[V], body: Term[V]) -> Self:
|
|
217
220
|
"""
|
|
218
221
|
Create an Abstraction binding multiple variables.
|
|
219
222
|
|
|
@@ -229,7 +232,8 @@ class Abstraction(Term[V]):
|
|
|
229
232
|
term = cls(variable, term)
|
|
230
233
|
return term
|
|
231
234
|
case _:
|
|
232
|
-
|
|
235
|
+
msg = "no variables to bind"
|
|
236
|
+
raise ValueError(msg)
|
|
233
237
|
|
|
234
238
|
def __str__(self) -> str:
|
|
235
239
|
"""
|
|
@@ -239,7 +243,7 @@ class Abstraction(Term[V]):
|
|
|
239
243
|
"""
|
|
240
244
|
return f"(λ{self.bound}.{self.body})"
|
|
241
245
|
|
|
242
|
-
def free_variables(self) ->
|
|
246
|
+
def free_variables(self) -> AbstractSet[V]:
|
|
243
247
|
"""
|
|
244
248
|
Calculate the free variables of this Term.
|
|
245
249
|
|
|
@@ -247,7 +251,7 @@ class Abstraction(Term[V]):
|
|
|
247
251
|
"""
|
|
248
252
|
return self.body.free_variables() - {self.bound}
|
|
249
253
|
|
|
250
|
-
def bound_variables(self) ->
|
|
254
|
+
def bound_variables(self) -> AbstractSet[V]:
|
|
251
255
|
"""
|
|
252
256
|
Calculate the free variables of this Term.
|
|
253
257
|
|
|
@@ -273,14 +277,12 @@ class Abstraction(Term[V]):
|
|
|
273
277
|
"""
|
|
274
278
|
if new == self.bound:
|
|
275
279
|
return self
|
|
276
|
-
|
|
277
|
-
return Abstraction(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
)
|
|
281
|
-
raise CollisionError("new variable would bind free variable in body", (new,))
|
|
280
|
+
if new not in self.body.free_variables():
|
|
281
|
+
return Abstraction(new, self.body.substitute(self.bound, Variable(new)))
|
|
282
|
+
msg = "new variable would bind free variable in body"
|
|
283
|
+
raise CollisionError(msg, (new,))
|
|
282
284
|
|
|
283
|
-
def eta_reduction(self) -> Term[V]:
|
|
285
|
+
def eta_reduction(self) -> Term[V]:
|
|
284
286
|
"""
|
|
285
287
|
Remove a useless abstraction.
|
|
286
288
|
|
|
@@ -291,11 +293,10 @@ class Abstraction(Term[V]):
|
|
|
291
293
|
case Application(f, Variable(x)) if x == self.bound and x not in f.free_variables():
|
|
292
294
|
return f
|
|
293
295
|
case _:
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
raise ValueError("abstraction is not useless")
|
|
296
|
+
msg = "abstraction is not useless"
|
|
297
|
+
raise ValueError(msg)
|
|
297
298
|
|
|
298
|
-
def accept(self, visitor:
|
|
299
|
+
def accept(self, visitor: Visitor[T, V]) -> T:
|
|
299
300
|
"""
|
|
300
301
|
Accept a visitor by calling visitors.Visitor.visit_abstraction.
|
|
301
302
|
|
|
@@ -313,8 +314,7 @@ class Abstraction(Term[V]):
|
|
|
313
314
|
:return: new term
|
|
314
315
|
"""
|
|
315
316
|
return Abstraction(
|
|
316
|
-
self.bound if bound is None else bound,
|
|
317
|
-
self.body if body is None else body
|
|
317
|
+
self.bound if bound is None else bound, self.body if body is None else body
|
|
318
318
|
)
|
|
319
319
|
|
|
320
320
|
|
|
@@ -333,7 +333,7 @@ class Application(Term[V]):
|
|
|
333
333
|
argument: Term[V]
|
|
334
334
|
|
|
335
335
|
@classmethod
|
|
336
|
-
def with_arguments(cls, abstraction: Term[V], arguments: Sequence[Term[V]]) ->
|
|
336
|
+
def with_arguments(cls, abstraction: Term[V], arguments: Sequence[Term[V]]) -> Self:
|
|
337
337
|
"""
|
|
338
338
|
Create an Application applying the abstraction to multiple arguments.
|
|
339
339
|
|
|
@@ -349,7 +349,8 @@ class Application(Term[V]):
|
|
|
349
349
|
term = cls(term, argument)
|
|
350
350
|
return term
|
|
351
351
|
case _:
|
|
352
|
-
|
|
352
|
+
msg = "no arguments to apply abstraction to"
|
|
353
|
+
raise ValueError(msg)
|
|
353
354
|
|
|
354
355
|
def __str__(self) -> str:
|
|
355
356
|
"""
|
|
@@ -359,7 +360,7 @@ class Application(Term[V]):
|
|
|
359
360
|
"""
|
|
360
361
|
return f"({self.abstraction} {self.argument})"
|
|
361
362
|
|
|
362
|
-
def free_variables(self) ->
|
|
363
|
+
def free_variables(self) -> AbstractSet[V]:
|
|
363
364
|
"""
|
|
364
365
|
Calculate the free variables of this Term.
|
|
365
366
|
|
|
@@ -367,7 +368,7 @@ class Application(Term[V]):
|
|
|
367
368
|
"""
|
|
368
369
|
return self.abstraction.free_variables() | self.argument.free_variables()
|
|
369
370
|
|
|
370
|
-
def bound_variables(self) ->
|
|
371
|
+
def bound_variables(self) -> AbstractSet[V]:
|
|
371
372
|
"""
|
|
372
373
|
Calculate the free variables of this Term.
|
|
373
374
|
|
|
@@ -389,9 +390,11 @@ class Application(Term[V]):
|
|
|
389
390
|
|
|
390
391
|
:return: if no beta reductions can be performed
|
|
391
392
|
"""
|
|
392
|
-
return
|
|
393
|
-
|
|
393
|
+
return (
|
|
394
|
+
not self.is_redex()
|
|
395
|
+
and self.abstraction.is_beta_normal_form()
|
|
394
396
|
and self.argument.is_beta_normal_form()
|
|
397
|
+
)
|
|
395
398
|
|
|
396
399
|
def beta_reduction(self) -> Term[V]:
|
|
397
400
|
"""
|
|
@@ -404,9 +407,10 @@ class Application(Term[V]):
|
|
|
404
407
|
case Abstraction(bound, body):
|
|
405
408
|
return body.substitute(bound, self.argument)
|
|
406
409
|
case _:
|
|
407
|
-
|
|
410
|
+
msg = "can not perform reduction without known Abstraction"
|
|
411
|
+
raise ValueError(msg)
|
|
408
412
|
|
|
409
|
-
def accept(self, visitor:
|
|
413
|
+
def accept(self, visitor: Visitor[T, V]) -> T:
|
|
410
414
|
"""
|
|
411
415
|
Accept a visitor by calling visitors.Visitor.visit_application.
|
|
412
416
|
|
|
@@ -415,7 +419,9 @@ class Application(Term[V]):
|
|
|
415
419
|
"""
|
|
416
420
|
return visitor.visit_application(self)
|
|
417
421
|
|
|
418
|
-
def replace(
|
|
422
|
+
def replace(
|
|
423
|
+
self, *, abstraction: Term[V] | None = None, argument: Term[V] | None = None
|
|
424
|
+
) -> Application[V]:
|
|
419
425
|
"""
|
|
420
426
|
Return a copy with specific attributes replaced.
|
|
421
427
|
|
|
@@ -425,5 +431,5 @@ class Application(Term[V]):
|
|
|
425
431
|
"""
|
|
426
432
|
return Application(
|
|
427
433
|
self.abstraction if abstraction is None else abstraction,
|
|
428
|
-
self.argument if argument is None else argument
|
|
434
|
+
self.argument if argument is None else argument,
|
|
429
435
|
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""Predefined Variables for all ASCII letters"""
|
|
2
|
+
|
|
3
|
+
from string import ascii_letters
|
|
4
|
+
|
|
5
|
+
from . import Variable
|
|
6
|
+
|
|
7
|
+
__all__ = tuple(ascii_letters)
|
|
8
|
+
|
|
9
|
+
# better IDE autocompletion
|
|
10
|
+
# ruff: noqa: E741
|
|
11
|
+
a, b, c, d, e, f, g, h, i, j = map(Variable, "abcdefghij")
|
|
12
|
+
k, l, m, n, o, p, q, r, s, t = map(Variable, "klmnopqrst")
|
|
13
|
+
u, v, w, x, y, z = map(Variable, "uvwxyz")
|
|
14
|
+
|
|
15
|
+
A, B, C, D, E, F, G, H, I, J = map(Variable, "ABCDEFGHIJ")
|
|
16
|
+
K, L, M, N, O, P, Q, R, S, T = map(Variable, "KLMNOPQRST")
|
|
17
|
+
U, V, W, X, Y, Z = map(Variable, "UVWXYZ")
|
|
@@ -1,21 +1,11 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
|
-
|
|
3
1
|
"""Implementations of natural numbers and arithmetic operators"""
|
|
4
2
|
|
|
5
3
|
from typing import Final
|
|
6
|
-
from . import Term, Variable, Abstraction, Application
|
|
7
|
-
from .logic import TRUE, FALSE
|
|
8
4
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"ADD",
|
|
14
|
-
"SUBTRACT",
|
|
15
|
-
"MULTIPLY",
|
|
16
|
-
"POWER",
|
|
17
|
-
"number"
|
|
18
|
-
)
|
|
5
|
+
from . import Abstraction, Application, Term, Variable
|
|
6
|
+
from .logic import FALSE, TRUE
|
|
7
|
+
|
|
8
|
+
__all__ = ("ADD", "ISZERO", "MULTIPLY", "POWER", "PREDECESSOR", "SUBTRACT", "SUCCESSOR", "number")
|
|
19
9
|
|
|
20
10
|
ISZERO: Final = Variable("n").apply_to(FALSE.abstract("x"), TRUE).abstract("n")
|
|
21
11
|
"""
|
|
@@ -26,12 +16,8 @@ if its argument is zero, :const:`lambda_calculus.terms.logic.FALSE` otherwise
|
|
|
26
16
|
SUCCESSOR: Final = Abstraction.curried(
|
|
27
17
|
("n", "f", "x"),
|
|
28
18
|
Application(
|
|
29
|
-
Variable("f"),
|
|
30
|
-
|
|
31
|
-
Variable("n"),
|
|
32
|
-
(Variable("f"), Variable("x"))
|
|
33
|
-
)
|
|
34
|
-
)
|
|
19
|
+
Variable("f"), Application.with_arguments(Variable("n"), (Variable("f"), Variable("x")))
|
|
20
|
+
),
|
|
35
21
|
)
|
|
36
22
|
"""
|
|
37
23
|
Term evaluating to its argument incremented by one.
|
|
@@ -43,19 +29,12 @@ PREDECESSOR: Final = Abstraction.curried(
|
|
|
43
29
|
Variable("n"),
|
|
44
30
|
(
|
|
45
31
|
Abstraction.curried(
|
|
46
|
-
("g", "h"),
|
|
47
|
-
Application(
|
|
48
|
-
Variable("h"),
|
|
49
|
-
Application(
|
|
50
|
-
Variable("g"),
|
|
51
|
-
Variable("f")
|
|
52
|
-
)
|
|
53
|
-
)
|
|
32
|
+
("g", "h"), Application(Variable("h"), Application(Variable("g"), Variable("f")))
|
|
54
33
|
),
|
|
55
34
|
Abstraction("u", Variable("x")),
|
|
56
35
|
Abstraction("u", Variable("u")),
|
|
57
|
-
)
|
|
58
|
-
)
|
|
36
|
+
),
|
|
37
|
+
),
|
|
59
38
|
)
|
|
60
39
|
"""
|
|
61
40
|
Term ealuating to its argument decremented by one.
|
|
@@ -65,51 +44,28 @@ ADD: Final = Abstraction.curried(
|
|
|
65
44
|
("m", "n", "f", "x"),
|
|
66
45
|
Application.with_arguments(
|
|
67
46
|
Variable("m"),
|
|
68
|
-
(
|
|
69
|
-
|
|
70
|
-
Application.with_arguments(
|
|
71
|
-
Variable("n"),
|
|
72
|
-
(Variable("f"), Variable("x"))
|
|
73
|
-
)
|
|
74
|
-
)
|
|
75
|
-
)
|
|
47
|
+
(Variable("f"), Application.with_arguments(Variable("n"), (Variable("f"), Variable("x")))),
|
|
48
|
+
),
|
|
76
49
|
)
|
|
77
50
|
"""
|
|
78
51
|
Term evaluating to the sum of its two arguments.
|
|
79
52
|
"""
|
|
80
53
|
|
|
81
54
|
SUBTRACT: Final = Abstraction.curried(
|
|
82
|
-
("m", "n"),
|
|
83
|
-
Application.with_arguments(
|
|
84
|
-
Variable("n"),
|
|
85
|
-
(PREDECESSOR, Variable("m"))
|
|
86
|
-
)
|
|
55
|
+
("m", "n"), Application.with_arguments(Variable("n"), (PREDECESSOR, Variable("m")))
|
|
87
56
|
)
|
|
88
57
|
"""
|
|
89
58
|
Term evaluating to the difference of its two arguments.
|
|
90
59
|
"""
|
|
91
60
|
|
|
92
61
|
MULTIPLY: Final = Abstraction.curried(
|
|
93
|
-
("m", "n", "f"),
|
|
94
|
-
Application(
|
|
95
|
-
Variable("m"),
|
|
96
|
-
Application(
|
|
97
|
-
Variable("n"),
|
|
98
|
-
Variable("f")
|
|
99
|
-
)
|
|
100
|
-
)
|
|
62
|
+
("m", "n", "f"), Application(Variable("m"), Application(Variable("n"), Variable("f")))
|
|
101
63
|
)
|
|
102
64
|
"""
|
|
103
65
|
Term evaluating to the product of its two arguments.
|
|
104
66
|
"""
|
|
105
67
|
|
|
106
|
-
POWER: Final = Abstraction.curried(
|
|
107
|
-
("b", "e"),
|
|
108
|
-
Application(
|
|
109
|
-
Variable("e"),
|
|
110
|
-
Variable("b")
|
|
111
|
-
)
|
|
112
|
-
)
|
|
68
|
+
POWER: Final = Abstraction.curried(("b", "e"), Application(Variable("e"), Variable("b")))
|
|
113
69
|
"""
|
|
114
70
|
Term evaluating to its first argument to the power of its second argument.
|
|
115
71
|
"""
|
|
@@ -124,12 +80,10 @@ def number(n: int) -> Abstraction[str]:
|
|
|
124
80
|
:return: requested term
|
|
125
81
|
"""
|
|
126
82
|
if n < 0:
|
|
127
|
-
|
|
83
|
+
msg = "number is not natural"
|
|
84
|
+
raise ValueError(msg)
|
|
128
85
|
f = Variable("f")
|
|
129
86
|
body: Term[str] = Variable("x")
|
|
130
87
|
for _ in range(n):
|
|
131
88
|
body = Application(f, body)
|
|
132
|
-
return Abstraction.curried(
|
|
133
|
-
("f", "x"),
|
|
134
|
-
body
|
|
135
|
-
)
|
|
89
|
+
return Abstraction.curried(("f", "x"), body)
|
|
@@ -1,38 +1,24 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
|
-
|
|
3
1
|
"""Common combinators"""
|
|
4
2
|
|
|
5
3
|
from typing import Final
|
|
6
|
-
from . import Variable, Application
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"K",
|
|
12
|
-
"I",
|
|
13
|
-
"B",
|
|
14
|
-
"C",
|
|
15
|
-
"W",
|
|
16
|
-
"DELTA",
|
|
17
|
-
"OMEGA"
|
|
18
|
-
)
|
|
5
|
+
from . import Application, Variable
|
|
6
|
+
|
|
7
|
+
__all__ = ("DELTA", "OMEGA", "B", "C", "I", "K", "S", "W", "Y")
|
|
19
8
|
|
|
20
9
|
Y: Final = Application(
|
|
21
|
-
Variable("g").apply_to(
|
|
22
|
-
|
|
23
|
-
).abstract("x"),
|
|
24
|
-
Variable("g").apply_to(
|
|
25
|
-
Variable("x").apply_to(Variable("x"))
|
|
26
|
-
).abstract("x")
|
|
10
|
+
Variable("g").apply_to(Variable("x").apply_to(Variable("x"))).abstract("x"),
|
|
11
|
+
Variable("g").apply_to(Variable("x").apply_to(Variable("x"))).abstract("x"),
|
|
27
12
|
).abstract("g")
|
|
28
13
|
"""
|
|
29
14
|
Y combinator used to define recursive terms.
|
|
30
15
|
"""
|
|
31
16
|
|
|
32
|
-
S: Final =
|
|
33
|
-
Variable("
|
|
34
|
-
Variable("y").apply_to(Variable("z"))
|
|
35
|
-
|
|
17
|
+
S: Final = (
|
|
18
|
+
Variable("x")
|
|
19
|
+
.apply_to(Variable("z"), Variable("y").apply_to(Variable("z")))
|
|
20
|
+
.abstract("x", "y", "z")
|
|
21
|
+
)
|
|
36
22
|
"""
|
|
37
23
|
S combinator of the SKI combinator calculus.
|
|
38
24
|
"""
|
|
@@ -42,37 +28,27 @@ K: Final = Variable("x").abstract("x", "y")
|
|
|
42
28
|
K combinator of the SKI combinator calculus.
|
|
43
29
|
"""
|
|
44
30
|
|
|
45
|
-
I: Final = Variable("x").abstract("x")
|
|
31
|
+
I: Final = Variable("x").abstract("x") # noqa: E741
|
|
46
32
|
"""
|
|
47
33
|
I combinator of the SKI combinator calculus.
|
|
48
34
|
"""
|
|
49
35
|
|
|
50
|
-
B: Final = Variable("x").apply_to(
|
|
51
|
-
Variable("y").apply_to(Variable("z"))
|
|
52
|
-
).abstract("x", "y", "z")
|
|
36
|
+
B: Final = Variable("x").apply_to(Variable("y").apply_to(Variable("z"))).abstract("x", "y", "z")
|
|
53
37
|
"""
|
|
54
38
|
B combinator of the BCKW combinator calculus.
|
|
55
39
|
"""
|
|
56
40
|
|
|
57
|
-
C: Final = Variable("x").apply_to(
|
|
58
|
-
Variable("z"),
|
|
59
|
-
Variable("y")
|
|
60
|
-
).abstract("x", "y", "z")
|
|
41
|
+
C: Final = Variable("x").apply_to(Variable("z"), Variable("y")).abstract("x", "y", "z")
|
|
61
42
|
"""
|
|
62
43
|
C combinator of the BCKW combinator calculus.
|
|
63
44
|
"""
|
|
64
45
|
|
|
65
|
-
W: Final = Variable("x").apply_to(
|
|
66
|
-
Variable("y"),
|
|
67
|
-
Variable("y")
|
|
68
|
-
).abstract("x", "y")
|
|
46
|
+
W: Final = Variable("x").apply_to(Variable("y"), Variable("y")).abstract("x", "y")
|
|
69
47
|
"""
|
|
70
48
|
W combinator of the BCKW combinator calculus.
|
|
71
49
|
"""
|
|
72
50
|
|
|
73
|
-
DELTA: Final = Variable("x").apply_to(
|
|
74
|
-
Variable("x")
|
|
75
|
-
).abstract("x")
|
|
51
|
+
DELTA: Final = Variable("x").apply_to(Variable("x")).abstract("x")
|
|
76
52
|
"""
|
|
77
53
|
Term applying its argument to itself.
|
|
78
54
|
"""
|
lambda_calculus/terms/logic.py
CHANGED
|
@@ -1,18 +1,10 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
|
-
|
|
3
1
|
"""Implementations of boolean values and logical operators"""
|
|
4
2
|
|
|
5
3
|
from typing import Final
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"FALSE",
|
|
11
|
-
"AND",
|
|
12
|
-
"OR",
|
|
13
|
-
"NOT",
|
|
14
|
-
"IF_THEN_ELSE"
|
|
15
|
-
)
|
|
4
|
+
|
|
5
|
+
from . import Abstraction, Application, Variable
|
|
6
|
+
|
|
7
|
+
__all__ = ("AND", "FALSE", "IF_THEN_ELSE", "NOT", "OR", "TRUE")
|
|
16
8
|
|
|
17
9
|
TRUE: Final = Abstraction.curried(("x", "y"), Variable("x"))
|
|
18
10
|
"""
|
|
@@ -25,16 +17,14 @@ Term representing False
|
|
|
25
17
|
"""
|
|
26
18
|
|
|
27
19
|
AND: Final = Abstraction.curried(
|
|
28
|
-
("p", "q"),
|
|
29
|
-
Application.with_arguments(Variable("p"), (Variable("q"), Variable("p")))
|
|
20
|
+
("p", "q"), Application.with_arguments(Variable("p"), (Variable("q"), Variable("p")))
|
|
30
21
|
)
|
|
31
22
|
"""
|
|
32
23
|
Term implementing logical conjunction between its two arguments.
|
|
33
24
|
"""
|
|
34
25
|
|
|
35
26
|
OR: Final = Abstraction.curried(
|
|
36
|
-
("p", "q"),
|
|
37
|
-
Application.with_arguments(Variable("p"), (Variable("p"), Variable("q")))
|
|
27
|
+
("p", "q"), Application.with_arguments(Variable("p"), (Variable("p"), Variable("q")))
|
|
38
28
|
)
|
|
39
29
|
"""
|
|
40
30
|
Term implementing logical disjunction between its two arguments.
|
|
@@ -46,8 +36,7 @@ Term performing logical negation of its argument.
|
|
|
46
36
|
"""
|
|
47
37
|
|
|
48
38
|
IF_THEN_ELSE: Final = Abstraction.curried(
|
|
49
|
-
("p", "a", "b"),
|
|
50
|
-
Application.with_arguments(Variable("p"), (Variable("a"), Variable("b")))
|
|
39
|
+
("p", "a", "b"), Application.with_arguments(Variable("p"), (Variable("a"), Variable("b")))
|
|
51
40
|
)
|
|
52
41
|
"""
|
|
53
42
|
Term evaluating to its second argument if its first argument is TRUE
|