lambda-calculus 3.1.0__py3-none-any.whl → 3.1.2__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 +54 -47
- lambda_calculus/terms/abc.py +2 -2
- 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 +19 -17
- 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.1.0.dist-info → lambda_calculus-3.1.2.dist-info}/METADATA +4 -4
- lambda_calculus-3.1.2.dist-info/RECORD +21 -0
- {lambda_calculus-3.1.0.dist-info → lambda_calculus-3.1.2.dist-info}/WHEEL +1 -1
- lambda_calculus-3.1.0.dist-info/RECORD +0 -20
- {lambda_calculus-3.1.0.dist-info → lambda_calculus-3.1.2.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.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (3, 1, 2)
|
|
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,27 +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
20
|
"abc",
|
|
21
21
|
"arithmetic",
|
|
22
|
+
"combinators",
|
|
22
23
|
"logic",
|
|
23
24
|
"pairs",
|
|
24
|
-
"combinators"
|
|
25
25
|
)
|
|
26
26
|
|
|
27
27
|
T = TypeVar("T")
|
|
@@ -52,25 +52,25 @@ class Term(Iterable["Term[V]"]):
|
|
|
52
52
|
|
|
53
53
|
:return: lambda term string
|
|
54
54
|
"""
|
|
55
|
-
raise NotImplementedError
|
|
55
|
+
raise NotImplementedError
|
|
56
56
|
|
|
57
57
|
@abstractmethod
|
|
58
|
-
def free_variables(self) ->
|
|
58
|
+
def free_variables(self) -> AbstractSet[V]:
|
|
59
59
|
"""
|
|
60
60
|
Calculate the free variables of this Term.
|
|
61
61
|
|
|
62
62
|
:return: variables not bound by an abstraction
|
|
63
63
|
"""
|
|
64
|
-
raise NotImplementedError
|
|
64
|
+
raise NotImplementedError
|
|
65
65
|
|
|
66
66
|
@abstractmethod
|
|
67
|
-
def bound_variables(self) ->
|
|
67
|
+
def bound_variables(self) -> AbstractSet[V]:
|
|
68
68
|
"""
|
|
69
69
|
Calculate the bound variables of this Term.
|
|
70
70
|
|
|
71
71
|
:return: variables bound by an abstraction
|
|
72
72
|
"""
|
|
73
|
-
raise NotImplementedError
|
|
73
|
+
raise NotImplementedError
|
|
74
74
|
|
|
75
75
|
@abstractmethod
|
|
76
76
|
def is_beta_normal_form(self) -> bool:
|
|
@@ -79,17 +79,17 @@ class Term(Iterable["Term[V]"]):
|
|
|
79
79
|
|
|
80
80
|
:return: if no beta reductions can be performed
|
|
81
81
|
"""
|
|
82
|
-
raise NotImplementedError
|
|
82
|
+
raise NotImplementedError
|
|
83
83
|
|
|
84
84
|
@abstractmethod
|
|
85
|
-
def accept(self, visitor:
|
|
85
|
+
def accept(self, visitor: Visitor[T, V]) -> T:
|
|
86
86
|
"""
|
|
87
87
|
Accept a visitor by calling his corresponding method.
|
|
88
88
|
|
|
89
89
|
:param visitor: Visitor to accept
|
|
90
90
|
:return: value returned by the visitors corresponding method
|
|
91
91
|
"""
|
|
92
|
-
raise NotImplementedError
|
|
92
|
+
raise NotImplementedError
|
|
93
93
|
|
|
94
94
|
def abstract(self, *variables: V) -> Abstraction[V]:
|
|
95
95
|
"""
|
|
@@ -141,7 +141,7 @@ class Variable(Term[V]):
|
|
|
141
141
|
name: V
|
|
142
142
|
|
|
143
143
|
@classmethod
|
|
144
|
-
def with_valid_name(cls, name: V) ->
|
|
144
|
+
def with_valid_name(cls, name: V) -> Self:
|
|
145
145
|
"""
|
|
146
146
|
Create an instance with a valid name.
|
|
147
147
|
|
|
@@ -151,10 +151,12 @@ class Variable(Term[V]):
|
|
|
151
151
|
"""
|
|
152
152
|
string = str(name)
|
|
153
153
|
if not string:
|
|
154
|
-
|
|
154
|
+
msg = "empty string representation"
|
|
155
|
+
raise ValueError(msg)
|
|
155
156
|
for character in string:
|
|
156
157
|
if character in "().λ" or character.isspace():
|
|
157
|
-
|
|
158
|
+
msg = f"invalid character: '{character}'"
|
|
159
|
+
raise ValueError(msg)
|
|
158
160
|
return cls(name)
|
|
159
161
|
|
|
160
162
|
def __str__(self) -> str:
|
|
@@ -165,7 +167,7 @@ class Variable(Term[V]):
|
|
|
165
167
|
"""
|
|
166
168
|
return str(self.name)
|
|
167
169
|
|
|
168
|
-
def free_variables(self) ->
|
|
170
|
+
def free_variables(self) -> AbstractSet[V]:
|
|
169
171
|
"""
|
|
170
172
|
Calculate the free variables of this Term.
|
|
171
173
|
|
|
@@ -173,7 +175,7 @@ class Variable(Term[V]):
|
|
|
173
175
|
"""
|
|
174
176
|
return {self.name}
|
|
175
177
|
|
|
176
|
-
def bound_variables(self) ->
|
|
178
|
+
def bound_variables(self) -> AbstractSet[V]:
|
|
177
179
|
"""
|
|
178
180
|
Calculate the bound variables of this Term.
|
|
179
181
|
|
|
@@ -189,7 +191,7 @@ class Variable(Term[V]):
|
|
|
189
191
|
"""
|
|
190
192
|
return True
|
|
191
193
|
|
|
192
|
-
def accept(self, visitor:
|
|
194
|
+
def accept(self, visitor: Visitor[T, V]) -> T:
|
|
193
195
|
"""
|
|
194
196
|
Accept a visitor by calling visitors.Visitor.visit_variable.
|
|
195
197
|
|
|
@@ -214,7 +216,7 @@ class Abstraction(Term[V]):
|
|
|
214
216
|
body: Term[V]
|
|
215
217
|
|
|
216
218
|
@classmethod
|
|
217
|
-
def curried(cls, variables: Sequence[V], body: Term[V]) ->
|
|
219
|
+
def curried(cls, variables: Sequence[V], body: Term[V]) -> Self:
|
|
218
220
|
"""
|
|
219
221
|
Create an Abstraction binding multiple variables.
|
|
220
222
|
|
|
@@ -230,7 +232,8 @@ class Abstraction(Term[V]):
|
|
|
230
232
|
term = cls(variable, term)
|
|
231
233
|
return term
|
|
232
234
|
case _:
|
|
233
|
-
|
|
235
|
+
msg = "no variables to bind"
|
|
236
|
+
raise ValueError(msg)
|
|
234
237
|
|
|
235
238
|
def __str__(self) -> str:
|
|
236
239
|
"""
|
|
@@ -240,7 +243,7 @@ class Abstraction(Term[V]):
|
|
|
240
243
|
"""
|
|
241
244
|
return f"(λ{self.bound}.{self.body})"
|
|
242
245
|
|
|
243
|
-
def free_variables(self) ->
|
|
246
|
+
def free_variables(self) -> AbstractSet[V]:
|
|
244
247
|
"""
|
|
245
248
|
Calculate the free variables of this Term.
|
|
246
249
|
|
|
@@ -248,7 +251,7 @@ class Abstraction(Term[V]):
|
|
|
248
251
|
"""
|
|
249
252
|
return self.body.free_variables() - {self.bound}
|
|
250
253
|
|
|
251
|
-
def bound_variables(self) ->
|
|
254
|
+
def bound_variables(self) -> AbstractSet[V]:
|
|
252
255
|
"""
|
|
253
256
|
Calculate the free variables of this Term.
|
|
254
257
|
|
|
@@ -274,12 +277,10 @@ class Abstraction(Term[V]):
|
|
|
274
277
|
"""
|
|
275
278
|
if new == self.bound:
|
|
276
279
|
return self
|
|
277
|
-
|
|
278
|
-
return Abstraction(
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
)
|
|
282
|
-
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,))
|
|
283
284
|
|
|
284
285
|
def eta_reduction(self) -> Term[V]:
|
|
285
286
|
"""
|
|
@@ -292,9 +293,10 @@ class Abstraction(Term[V]):
|
|
|
292
293
|
case Application(f, Variable(x)) if x == self.bound and x not in f.free_variables():
|
|
293
294
|
return f
|
|
294
295
|
case _:
|
|
295
|
-
|
|
296
|
+
msg = "abstraction is not useless"
|
|
297
|
+
raise ValueError(msg)
|
|
296
298
|
|
|
297
|
-
def accept(self, visitor:
|
|
299
|
+
def accept(self, visitor: Visitor[T, V]) -> T:
|
|
298
300
|
"""
|
|
299
301
|
Accept a visitor by calling visitors.Visitor.visit_abstraction.
|
|
300
302
|
|
|
@@ -312,8 +314,7 @@ class Abstraction(Term[V]):
|
|
|
312
314
|
:return: new term
|
|
313
315
|
"""
|
|
314
316
|
return Abstraction(
|
|
315
|
-
self.bound if bound is None else bound,
|
|
316
|
-
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
|
|
317
318
|
)
|
|
318
319
|
|
|
319
320
|
|
|
@@ -332,7 +333,7 @@ class Application(Term[V]):
|
|
|
332
333
|
argument: Term[V]
|
|
333
334
|
|
|
334
335
|
@classmethod
|
|
335
|
-
def with_arguments(cls, abstraction: Term[V], arguments: Sequence[Term[V]]) ->
|
|
336
|
+
def with_arguments(cls, abstraction: Term[V], arguments: Sequence[Term[V]]) -> Self:
|
|
336
337
|
"""
|
|
337
338
|
Create an Application applying the abstraction to multiple arguments.
|
|
338
339
|
|
|
@@ -348,7 +349,8 @@ class Application(Term[V]):
|
|
|
348
349
|
term = cls(term, argument)
|
|
349
350
|
return term
|
|
350
351
|
case _:
|
|
351
|
-
|
|
352
|
+
msg = "no arguments to apply abstraction to"
|
|
353
|
+
raise ValueError(msg)
|
|
352
354
|
|
|
353
355
|
def __str__(self) -> str:
|
|
354
356
|
"""
|
|
@@ -358,7 +360,7 @@ class Application(Term[V]):
|
|
|
358
360
|
"""
|
|
359
361
|
return f"({self.abstraction} {self.argument})"
|
|
360
362
|
|
|
361
|
-
def free_variables(self) ->
|
|
363
|
+
def free_variables(self) -> AbstractSet[V]:
|
|
362
364
|
"""
|
|
363
365
|
Calculate the free variables of this Term.
|
|
364
366
|
|
|
@@ -366,7 +368,7 @@ class Application(Term[V]):
|
|
|
366
368
|
"""
|
|
367
369
|
return self.abstraction.free_variables() | self.argument.free_variables()
|
|
368
370
|
|
|
369
|
-
def bound_variables(self) ->
|
|
371
|
+
def bound_variables(self) -> AbstractSet[V]:
|
|
370
372
|
"""
|
|
371
373
|
Calculate the free variables of this Term.
|
|
372
374
|
|
|
@@ -388,9 +390,11 @@ class Application(Term[V]):
|
|
|
388
390
|
|
|
389
391
|
:return: if no beta reductions can be performed
|
|
390
392
|
"""
|
|
391
|
-
return
|
|
392
|
-
|
|
393
|
+
return (
|
|
394
|
+
not self.is_redex()
|
|
395
|
+
and self.abstraction.is_beta_normal_form()
|
|
393
396
|
and self.argument.is_beta_normal_form()
|
|
397
|
+
)
|
|
394
398
|
|
|
395
399
|
def beta_reduction(self) -> Term[V]:
|
|
396
400
|
"""
|
|
@@ -403,9 +407,10 @@ class Application(Term[V]):
|
|
|
403
407
|
case Abstraction(bound, body):
|
|
404
408
|
return body.substitute(bound, self.argument)
|
|
405
409
|
case _:
|
|
406
|
-
|
|
410
|
+
msg = "can not perform reduction without known Abstraction"
|
|
411
|
+
raise ValueError(msg)
|
|
407
412
|
|
|
408
|
-
def accept(self, visitor:
|
|
413
|
+
def accept(self, visitor: Visitor[T, V]) -> T:
|
|
409
414
|
"""
|
|
410
415
|
Accept a visitor by calling visitors.Visitor.visit_application.
|
|
411
416
|
|
|
@@ -414,7 +419,9 @@ class Application(Term[V]):
|
|
|
414
419
|
"""
|
|
415
420
|
return visitor.visit_application(self)
|
|
416
421
|
|
|
417
|
-
def replace(
|
|
422
|
+
def replace(
|
|
423
|
+
self, *, abstraction: Term[V] | None = None, argument: Term[V] | None = None
|
|
424
|
+
) -> Application[V]:
|
|
418
425
|
"""
|
|
419
426
|
Return a copy with specific attributes replaced.
|
|
420
427
|
|
|
@@ -424,5 +431,5 @@ class Application(Term[V]):
|
|
|
424
431
|
"""
|
|
425
432
|
return Application(
|
|
426
433
|
self.abstraction if abstraction is None else abstraction,
|
|
427
|
-
self.argument if argument is None else argument
|
|
434
|
+
self.argument if argument is None else argument,
|
|
428
435
|
)
|
lambda_calculus/terms/abc.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
#!/usr/bin/python3
|
|
2
|
-
|
|
3
1
|
"""Predefined Variables for all ASCII letters"""
|
|
4
2
|
|
|
5
3
|
from string import ascii_letters
|
|
4
|
+
|
|
6
5
|
from . import Variable
|
|
7
6
|
|
|
8
7
|
__all__ = tuple(ascii_letters)
|
|
9
8
|
|
|
10
9
|
# better IDE autocompletion
|
|
10
|
+
# ruff: noqa: E741
|
|
11
11
|
a, b, c, d, e, f, g, h, i, j = map(Variable, "abcdefghij")
|
|
12
12
|
k, l, m, n, o, p, q, r, s, t = map(Variable, "klmnopqrst")
|
|
13
13
|
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
|