2222# General config
2323#########################################################
2424
25- # Name of the top-level package of your library.
25+ # Name of the top-level package of the library.
2626#
2727# This is also the top level of its source tree, relative to the top-level project directory setup.py resides in.
2828#
2929libname = "unpythonic"
3030
3131# Short description for package list on PyPI
3232#
33- SHORTDESC = "Python meets (selected parts of) Lisp and Haskell."
33+ SHORTDESC = "Missing batteries included: Python meets Lisp and Haskell."
3434
3535# Long description for package homepage on PyPI
3636#
3737DESC = """We provide missing features for Python, mainly from the list processing
38- tradition, but with some haskellisms mixed in. We place a special emphasis on
39- **clear, pythonic syntax**. For the adventurous, we also provide a set of
40- syntactic macros that are designed to work together.
38+ tradition, but with some haskellisms mixed in. For the adventurous, we include
39+ a set of syntactic macros (using MacroPy) that are designed to work together.
4140
42- Design considerations are simplicity, robustness, and minimal dependencies
43- (currently none required; MacroPy optional, to enable the syntactic macros).
44- In macros we aim at orthogonality, combinability, and clear, pythonic syntax.
41+ We place a special emphasis on **clear, pythonic syntax**. Design considerations
42+ are simplicity, robustness, and minimal dependencies.
4543
46- Features include tail call optimization (TCO), TCO'd loops in FP style, call/ec,
47- let & letrec, assign-once, multi-expression lambdas, def as a code block,
48- dynamic assignment, memoize (also for generators and iterables), compose,
44+ Without MacroPy, our features include tail call optimization (TCO), TCO'd loops
45+ in FP style, call/ec, let & letrec, assign-once, multi-expression lambdas,
46+ dynamic assignment (a.k.a. *parameterize*, *special variables*), memoization
47+ (also for generators and iterables), currying, function composition,
4948folds and scans (left and right), unfold, lazy partial unpacking of iterables,
50- functional sequence updates, pythonic lispy linked lists.
49+ functional update for sequences, and pythonic lispy linked lists (``cons``) .
5150
52- We provide a curry that passes extra arguments through on the right, and calls
53- a callable return value on the remaining arguments. This is now valid Python::
51+ Our curry slightly modifies Python's reduction rules. It passes any extra
52+ arguments through on the right, and calls a callable return value on the
53+ remaining arguments, so that we can::
5454
5555 mymap = lambda f: curry(foldr, composerc(cons, f), nil)
5656 myadd = lambda a, b: a + b
6060 look = lambda n1, n2: composel(*with_n((n1, drop), (n2, take)))
6161 assert tuple(curry(look, 5, 10, range(20))) == tuple(range(5, 15))
6262
63- As macros we provide e.g. automatic currying, automatic tail-call optimization,
64- continuations (``call/cc``), lexically scoped ``let`` and ``do``, implicit
65- return statements, and easy-to-use multi-expression lambdas with local variables .
63+ If MacroPy is installed, ``unpythonic.syntax`` becomes available. It provides
64+ macros that essentially extend the Python language, adding features that would
65+ be either complicated or impossible to provide (and/or use) otherwise .
6666
67- For a taste of the macros::
67+ Macro features include automatic currying, automatic tail-call optimization,
68+ continuations (``call/cc`` for Python), ``let-syntax`` (splice code at macro
69+ expansion time), lexically scoped ``let`` and ``do`` with lean syntax,
70+ implicit return statements, and easy-to-use multi-expression lambdas
71+ with local variables.
6872
69- # let, letseq, letrec with no boilerplate
73+ The TCO macro has a fairly extensive expression analyzer, so things like ``and``,
74+ ``or``, ``a if p else b`` and any uses of the ``do[]`` and ``let[]`` macros are
75+ accounted for when performing the tail-call transformation.
76+
77+ The continuation system is based on a semi-automated partial conversion into
78+ continuation-passing style (CPS), with continuations represented as closures.
79+ It also automatically applies TCO, using the same machinery as the TCO macro.
80+
81+ Macro examples::
82+
83+ # let, letseq (let*), letrec with no boilerplate
7084 a = let((x, 17),
7185 (y, 23))[
7286 (x, y)]
7387
88+ # alternate haskelly syntax
89+ a = let[((x, 21),(y, 17), (z, 4)) in x + y + z]
90+ a = let[x + y + z, where((x, 21), (y, 17), (z, 4))]
91+
7492 # cond: multi-branch "if" expression
7593 answer = lambda x: cond[x == 2, "two",
7694 x == 3, "three",
@@ -153,7 +171,7 @@ def g(x):
153171 (print, (mymap, double, (q, 1, 2, 3)))
154172 assert (mymap, double, (q, 1, 2, 3)) == ll(2, 4, 6)
155173
156- # essentially call/cc for Python
174+ # call/cc for Python
157175 with continuations:
158176 stack = []
159177 def amb(lst, *, cc): # McCarthy's amb operator
@@ -169,19 +187,42 @@ def fail(*, cc):
169187 f = stack.pop()
170188 return f()
171189
172- def pyth( *, cc):
173- with bind [amb(tuple(range(1, 21 )))] as z:
174- with bind [amb(tuple(range(1, z+1)))] as y:
175- with bind [amb(tuple(range(1, y+1)))] as x: # <-- the call/cc
176- if x*x + y*y != z*z: # body is the cont
177- return fail()
178- return x, y, z
179- x = pyth( )
190+ def pythagorean_triples(maxn, *, cc):
191+ z = call_cc [amb(tuple(range(1, maxn+1 )))]
192+ y = call_cc [amb(tuple(range(1, z+1)))]
193+ x = call_cc [amb(tuple(range(1, y+1)))]
194+ if x*x + y*y != z*z:
195+ return fail()
196+ return x, y, z
197+ x = pythagorean_triples(20 )
180198 while x:
181199 print(x)
182200 x = fail()
183201
184- For documentation and full examples, see the project's GitHub homepage.
202+ # if Python didn't already have generators, we could add them with call/cc:
203+ with continuations:
204+ @dlet((k, None))
205+ def g(*, cc):
206+ if k:
207+ return k()
208+ def my_yield(value, *, cc):
209+ k << cc
210+ cc = identity
211+ return value
212+ # generator body
213+ call_cc[my_yield(1)]
214+ call_cc[my_yield(2)]
215+ call_cc[my_yield(3)]
216+ out = []
217+ x = g()
218+ while x is not None:
219+ out.append(x)
220+ x = g()
221+ assert out == [1, 2, 3]
222+
223+ For documentation and full examples, see the project's GitHub homepage,
224+ and the docstrings of the individual features. For even more examples,
225+ see the unit tests included in the source distribution.
185226"""
186227
187228# Set up data files for packaging.
0 commit comments