Skip to content

Commit 11d8ece

Browse files
committed
update project description
1 parent 33e334b commit 11d8ece

File tree

1 file changed

+70
-29
lines changed

1 file changed

+70
-29
lines changed

setup.py

Lines changed: 70 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,35 @@
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
#
2929
libname="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
#
3737
DESC="""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,
4948
folds 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
@@ -60,17 +60,35 @@
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

Comments
 (0)