Skip to content

Commit 2641af9

Browse files
committed
update comment and docstring (again)
1 parent 775a3e3 commit 2641af9

1 file changed

Lines changed: 26 additions & 17 deletions

File tree

unpythonic/amb.py

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
This is essentially a toy that has no more power than list comprehensions
55
or nested for loops. An important feature of McCarthy's amb operator is its
66
nonlocality - being able to jump back to a choice point, even after the
7-
dynamic extent of the function where it resides. (Sounds a lot like call/cc;
8-
which is how amb is usually implemented in Scheme.)
7+
dynamic extent of the function where it resides. (Sounds a lot like
8+
``call/cc``; which is how ``amb`` is usually implemented in Scheme.)
99
1010
Instead, what we have here is essentially a tuple comprehension that:
1111
@@ -17,11 +17,16 @@
1717
The implementation is based on the List monad. This is a hack with the bare
1818
minimum of components to make it work, complete with a semi-usable syntax.
1919
20-
For a friendlier syntax, if you use MacroPy, see ``unpythonic.syntax.forall``.
20+
If you use MacroPy:
2121
22-
If you need more monads, look into OSlash.
22+
- For a friendlier syntax for this, see ``unpythonic.syntax.forall``.
2323
24-
Or if you want to roll your own, the parts of this module come from:
24+
- If you need the full(-ish) power of ``call/cc``, see
25+
``unpythonic.syntax.continuations`` (which can implement ``amb``).
26+
27+
If you need more monads, look into the ``OSlash`` library.
28+
29+
If you want to roll your own monads, the parts for this module come from:
2530
https://github.com/Technologicat/python-3-scicomp-intro/blob/master/examples/monads.py
2631
"""
2732

@@ -47,7 +52,9 @@ def choice(**binding):
4752
for k, v in binding.items(): # just one but we don't know its name
4853
return Assignment(k, v)
4954

50-
# For a cleaner solution, see unpythonic.syntax.forall.
55+
# Hacky code generator, because Python has ``eval`` but no syntactic macros.
56+
# For a cleaner solution based on AST transformation with MacroPy,
57+
# see unpythonic.syntax.forall.
5158
def forall(*lines):
5259
"""Nondeterministically evaluate lines.
5360
@@ -76,25 +83,26 @@ def forall(*lines):
7683
- All choices are evaluated, depth first, and set of results is
7784
returned as a tuple.
7885
79-
- The last line describes one item of the return value.
80-
8186
- If a line returns an iterable, it is implicitly converted into a List
8287
monad containing the same items.
8388
8489
- This applies also to the RHS of a ``choice``.
8590
86-
- If a line returns a single item, it is wrapped into a singleton List.
87-
88-
- The final result is **not** unpacked. This allows easily returning
89-
a tuple from the computation.
91+
- As the only exception, the last line describes one item of the return
92+
value; there the implicit conversion is skipped.
9093
91-
- The final result is converted from List monad to tuple for output.
94+
This allows easily returning a tuple (as one result item) from the
95+
computation, as in the above pythagorean triples example.
9296
93-
- The variables currently picked by the choices live in the environment.
94-
To access it, use a ``lambda e: ...`` like in ``unpythonic.letrec``.
97+
- If a line returns a single item, it is wrapped into a singleton List
98+
(a List containing that one item).
9599
96-
- The List monad is internal to this module.
100+
- The final result (containing all the results) is converted from
101+
List monad to tuple for output.
97102
103+
- The values currently picked by the choices are bound to names in
104+
the environment. To access it, use a ``lambda e: ...`` like in
105+
``unpythonic.letrec``.
98106
99107
Quick vocabulary for haskellers:
100108
- ``forall(...)`` = ``do ...``
@@ -185,7 +193,8 @@ def begin(*exprs): # args eagerly evaluated by Python
185193

186194
# print(allcode) # DEBUG
187195

188-
# The eval'd code doesn't close over the current lexical scope,
196+
# The eval'd code doesn't close over the current lexical scope at the site
197+
# of the eval call, but runs in its own initially blank environment,
189198
# so provide the necessary names as its globals.
190199
mlst = eval(allcode, {"e": e, "bodys": bodys, "begin": begin, "monadify": monadify})
191200
return tuple(mlst)

0 commit comments

Comments
 (0)