Skip to content

Commit aed614a

Browse files
committed
improve docstring of package visitors
1 parent 84ef306 commit aed614a

File tree

5 files changed

+170
-25
lines changed

5 files changed

+170
-25
lines changed

docs/api/visitors.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Package visitors
55
:maxdepth: 2
66

77
visitors/substitution
8+
visitors/normalisation
89
visitors/walking
910

1011
.. automodule:: lambda_calculus.visitors
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Module normalisation
2+
====================
3+
4+
.. toctree::
5+
:maxdepth: 2
6+
7+
.. automodule:: lambda_calculus.visitors.normalisation
8+
:members:

lambda_calculus/visitors/__init__.py

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,49 +22,98 @@
2222

2323
class Visitor(ABC, Generic[T, V]):
2424
"""
25-
ABC for Visitors visiting Terms
26-
The visitor is responsible to visit child terms
25+
ABC for Visitors visiting Terms.
26+
27+
The visitor is responsible for visiting child terms.
28+
29+
Type Variables:
30+
31+
T: represents the type of the result produced by visiting terms
32+
V: represents the type of variables used in terms
2733
"""
2834

2935
__slots__ = ()
3036

3137
@final
3238
def visit(self, term: terms.Term[V]) -> T:
33-
"""visit a term"""
39+
"""
40+
Visit a term
41+
42+
:param term: term to visit
43+
:return: Result of calling :meth:`.terms.Term.accept` with self as argument
44+
"""
3445
return term.accept(self)
3546

3647
@abstractmethod
3748
def visit_variable(self, variable: terms.Variable[V]) -> T:
38-
"""visit a Variable term"""
49+
"""
50+
Visit a Variable term.
51+
52+
:param variable: variable term to visit
53+
:return: value as required by its type variable
54+
"""
3955
raise NotImplementedError()
4056

4157
@abstractmethod
4258
def visit_abstraction(self, abstraction: terms.Abstraction[V]) -> T:
43-
"""visit an Abstraction term"""
59+
"""
60+
Visit an Abstraction term
61+
62+
The body is not automatically visited.
63+
64+
:param abstraction: abstraction term to visit
65+
:return: value as required by its type variable
66+
"""
4467
raise NotImplementedError()
4568

4669
@abstractmethod
4770
def visit_application(self, application: terms.Application[V]) -> T:
48-
"""visit an Application term"""
71+
"""
72+
Visit an Application term
73+
74+
The abstraction and argument are not automatically visited.
75+
76+
:param appliation: application term to visit
77+
:return: value as required by its type variable
78+
"""
4979
raise NotImplementedError()
5080

5181

5282
class BottomUpVisitor(Visitor[T, V]):
53-
"""ABC for visitors which visit child terms first"""
83+
"""
84+
ABC for visitors which visit child terms first
85+
86+
Child terms are automatically visited.
87+
"""
5488

5589
__slots__ = ()
5690

5791
@final
5892
def visit_abstraction(self, abstraction: terms.Abstraction[V]) -> T:
59-
"""visit an Abstraction term"""
93+
"""
94+
Visit an Abstraction term
95+
96+
The body is visited before calling :meth:`ascend_abstraction`.
97+
98+
:param abstraction: abstraction term to visit
99+
:return: value returned by :meth:`ascend_abstraction`
100+
"""
60101
return self.ascend_abstraction(
61102
abstraction,
62103
abstraction.body.accept(self)
63104
)
64105

65106
@final
66107
def visit_application(self, application: terms.Application[V]) -> T:
67-
"""visit an Application term"""
108+
"""
109+
Visit an Application term
110+
111+
The abstraction and argument are visited
112+
before calling :meth:`ascend_application`.
113+
114+
:param application: application term to visit
115+
:return: value returned by :meth:`ascend_application`
116+
"""
68117
return self.ascend_application(
69118
application,
70119
application.abstraction.accept(self),
@@ -73,26 +122,53 @@ def visit_application(self, application: terms.Application[V]) -> T:
73122

74123
@abstractmethod
75124
def ascend_abstraction(self, abstraction: terms.Abstraction[V], body: T) -> T:
76-
"""visit an Abstraction term after visiting its body"""
125+
"""
126+
Visit an Abstraction term after visiting its body.
127+
128+
:param abstraction: abstraction term to visit
129+
:param body: value produced by visiting its body
130+
:return: value as required by its type variable
131+
"""
77132
raise NotImplementedError()
78133

79134
@abstractmethod
80135
def ascend_application(self, application: terms.Application[V], abstraction: T, argument: T) -> T:
81-
"""visit an Application term after visiting its abstraction and argument"""
136+
"""
137+
Visit an Application term after visiting its abstraction and argument.
138+
139+
:param application: application term to visit
140+
:param abstraction: value produced by visiting its abstraction
141+
:param argument: value produced by visiting its argument
142+
:return: value as required by its type variable
143+
"""
82144
raise NotImplementedError()
83145

84146

85147
class DeferrableVisitor(Visitor[T, V]):
86-
"""ABC for visitors which can visit terms top down lazyly"""
148+
"""
149+
ABC for visitors which can visit terms top down lazyly.
150+
"""
87151

88152
__slots__ = ()
89153

90154
@abstractmethod
91155
def defer_abstraction(self, abstraction: terms.Abstraction[V]) -> tuple[T, DeferrableVisitor[T, V] | None]:
92-
"""visit an Abstraction term and return the visitor used to visit its body"""
156+
"""
157+
Visit an Abstraction term.
158+
159+
:param abstraction: abstraction term to visit
160+
:return: tuple containing a value as required by its type variable
161+
and a visitor to be used for visiting its body
162+
"""
93163
raise NotImplementedError()
94164

95165
@abstractmethod
96166
def defer_application(self, application: terms.Application[V]) -> tuple[T, DeferrableVisitor[T, V] | None, DeferrableVisitor[T, V] | None]:
97-
"""visit an Application term and return the visitors used to visit its abstraction and argument"""
167+
"""
168+
Visit an Application term.
169+
170+
:param abstraction: application term to visit
171+
:return: tuple containing a value as required by its type variable
172+
and visitors to be used for visiting its abstraction and argument
173+
"""
98174
raise NotImplementedError()

lambda_calculus/visitors/normalisation.py

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/python3
22

3-
"""Visitor for normalisation"""
3+
"""Visitor for term normalisation"""
44

55
from __future__ import annotations
66
from collections.abc import Iterator
@@ -22,7 +22,9 @@
2222

2323
@unique
2424
class Conversion(Enum):
25-
"""Conversion performed by normalisation"""
25+
"""
26+
Conversion performed by normalisation
27+
"""
2628
ALPHA = 0
2729
BETA = 1
2830

@@ -32,28 +34,54 @@ class BetaNormalisingVisitor(Visitor[Iterator[Step], str]):
3234
"""
3335
Visitor which transforms a term into its beta normal form,
3436
yielding intermediate steps until it is reached
37+
38+
No steps are yielded if the term is already in its beta normal form.
39+
40+
Remember that some terms dont thave a beta normal form and
41+
can cause infinite recursion.
3542
"""
3643

3744
__slots__ = ()
3845

3946
def skip_intermediate(self, term: terms.Term[str]) -> terms.Term[str]:
40-
"""return the beta normal form directly"""
47+
"""
48+
Calculate the beta normal form directly.
49+
50+
:param term: term which should be transformed into ist beta normal form
51+
:return: new term representing the beta normal form if it exists
52+
"""
4153
result = term
4254
for _, intermediate in term.accept(self):
4355
result = intermediate
4456
return result
4557

4658
def visit_variable(self, variable: terms.Variable[str]) -> Iterator[Step]:
47-
"""visit a Variable term"""
59+
"""
60+
Visit a Variable term.
61+
62+
:param variable: variable term to visit
63+
:return: empty Iterator, variables are already in beta normal form
64+
"""
4865
return iter(())
4966

5067
def visit_abstraction(self, abstraction: terms.Abstraction[str]) -> Iterator[Step]:
51-
"""visit an Abstraction term"""
68+
"""
69+
Visit an Abstraction term.
70+
71+
:param abstraction: abstraction term to visit
72+
:return: Iterator yielding steps performed on its body
73+
"""
5274
results = abstraction.body.accept(self)
5375
return map(lambda s: (s[0], terms.Abstraction(abstraction.bound, s[1])), results)
5476

5577
def beta_reducation(self, abstraction: terms.Abstraction[str], argument: terms.Term[str]) -> Generator[Step, None, terms.Term[str]]:
56-
"""perform beta reduction of an application"""
78+
"""
79+
Perform beta reduction of an application.
80+
81+
:param abstraction: abstraction of the application
82+
:param argument: argument of the application
83+
:return: Generator yielding steps and returning the reduced term
84+
"""
5785
conversions = CountingSubstitution.from_substitution(abstraction.bound, argument).trace()
5886
reduced = yield from map(
5987
lambda body: (
@@ -66,7 +94,15 @@ def beta_reducation(self, abstraction: terms.Abstraction[str], argument: terms.T
6694
return reduced # type: ignore
6795

6896
def visit_application(self, application: terms.Application[str]) -> Iterator[Step]:
69-
"""visit an Application term"""
97+
"""
98+
Visit an Application term
99+
100+
The abstraction and argument are not automatically visited.
101+
102+
:param application: application term to visit
103+
:return: steps for performing beta reduction if possible
104+
and performed on its result or abstraction and argument
105+
"""
70106
if isinstance(application.abstraction, terms.Abstraction):
71107
# normal order dictates we reduce the leftmost outermost redex first
72108
reduced = yield from self.beta_reducation(application.abstraction, application.argument)

lambda_calculus/visitors/walking.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,35 @@
1616

1717

1818
class DepthFirstVisitor(BottomUpVisitor[Iterator["terms.Term[V]"], V]):
19-
"""Visitor yielding subterms depth first"""
19+
"""
20+
Visitor yielding subterms depth first
21+
22+
Type Variables:
23+
24+
V: represents the type of variables used in terms
25+
"""
2026

2127
def visit_variable(self, variable: terms.Variable[V]) -> Iterator[terms.Term[V]]:
22-
"""visit a Variable term"""
28+
"""
29+
Visit a Variable term.
30+
31+
:param variable: variable term to visit
32+
:return: Iterator yielding the term
33+
"""
2334
yield variable
2435

2536
def ascend_abstraction(
2637
self,
2738
abstraction: terms.Abstraction[V],
2839
body: Iterator[terms.Term[V]]
2940
) -> Iterator[terms.Term[V]]:
30-
"""visit an Abstraction term after visiting its body"""
41+
"""
42+
Visit an Abstraction term after visiting its body.
43+
44+
:param abstraction: abstraction term to visit
45+
:param body: Iterator produced by visiting its body
46+
:return: term appended to its body Iterator
47+
"""
3148
yield from body
3249
yield abstraction
3350

@@ -37,7 +54,14 @@ def ascend_application(
3754
abstraction: Iterator[terms.Term[V]],
3855
argument: Iterator[terms.Term[V]]
3956
) -> Iterator[terms.Term[V]]:
40-
"""visit an Application term after visiting its abstraction and argument"""
57+
"""
58+
Visit an Application term after visiting its abstraction and argument.
59+
60+
:param application: application term to visit
61+
:param abstraction: Iterator produced by visiting its abstraction
62+
:param argument: Iterator produced by visiting its argument
63+
:return: term appended to its abstraction and argument Iterators
64+
"""
4165
yield from abstraction
4266
yield from argument
4367
yield application

0 commit comments

Comments
 (0)