Skip to content

Commit 648e0e3

Browse files
committed
more logical suffix ordering in compose functions
1 parent f6538a9 commit 648e0e3

3 files changed

Lines changed: 51 additions & 59 deletions

File tree

unpythonic/fun.py

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
__all__ = ["memoize", "curry", "iscurried",
1212
"flip", "rotate",
1313
"apply", "identity", "const", "notf", "andf", "orf",
14-
"composer1", "composel1", "composeri1", "composeli1", # single arg
14+
"composer1", "composel1", "composer1i", "composel1i", # single arg
1515
"composer", "composel", "composeri", "composeli", # multi-arg
16-
"composerc", "composelc", "composeric", "composelic", # multi-arg w/ curry
16+
"composerc", "composelc", "composerci", "composelci", # multi-arg w/ curry
1717
"to1st", "to2nd", "tokth", "tolast", "to"]
1818

1919
from functools import wraps, partial
@@ -110,9 +110,9 @@ def foo(a, b, *, c, d):
110110
on the remaining positional args::
111111
112112
map_one = lambda f: (curry(foldr))(composer(cons, to1st(f)), nil)
113-
assert curry(map_one)(double, (1, 2, 3)) == (2, 4, 6)
113+
assert curry(map_one)(double, ll(1, 2, 3)) == ll(2, 4, 6)
114114
115-
In the above example, ``map_one`` has arity 1, so the tuple ``(1, 2, 3)``
115+
In the above example, ``map_one`` has arity 1, so the arg ``ll(1, 2, 3)``
116116
is extra. The result of ``map_one`` is a callable, so it is then
117117
invoked on this tuple.
118118
@@ -131,6 +131,10 @@ def foo(a, b, *, c, d):
131131
132132
assert curry(double, 2, "foo") == (4, "foo")
133133
134+
mymap = lambda f: curry(foldr, composerc(cons, f), nil)
135+
add = lambda x, y: x + y
136+
assert curry(mymap, add, ll(1, 2, 3), ll(4, 5, 6)) == ll(5, 7, 9)
137+
134138
from functools import partial
135139
from unpythonic import curry, composel, drop, take
136140
@@ -360,7 +364,7 @@ def composer1(*fs):
360364
inc_then_double = composer1(double, inc)
361365
assert inc_then_double(3) == 8
362366
"""
363-
return composeri1(fs)
367+
return composer1i(fs)
364368

365369
def composel1(*fs):
366370
"""Like composel, but limited to one-argument functions. Faster.
@@ -369,17 +373,17 @@ def composel1(*fs):
369373
370374
double = lambda x: 2*x
371375
inc = lambda x: x+1
372-
double_then_inc = composel(double, inc)
376+
double_then_inc = composel1(double, inc)
373377
assert double_then_inc(3) == 7
374378
"""
375-
return composeli1(fs)
379+
return composel1i(fs)
376380

377-
def composeri1(iterable): # this is just to insert a docstring
378-
"""Like composeri, but limited to one-argument functions. Faster."""
381+
def composer1i(iterable): # this is just to insert a docstring
382+
"""Like composer1, but read the functions from an iterable."""
379383
return _compose1_right(iterable)
380384

381-
def composeli1(iterable):
382-
"""Like composeli, but limited to one-argument functions. Faster."""
385+
def composel1i(iterable):
386+
"""Like composel1, but read the functions from an iterable."""
383387
return _compose1_left(iterable)
384388

385389
def _make_compose(direction): # "left", "right"
@@ -425,15 +429,13 @@ def composel(*fs):
425429
return composeli(fs)
426430

427431
def composeri(iterable):
428-
"""Like composer, but takes an iterable of functions to compose."""
432+
"""Like composer, but read the functions from an iterable."""
429433
return _compose_right(iterable)
430434

431435
def composeli(iterable):
432-
"""Like composel, but takes an iterable of functions to compose."""
436+
"""Like composel, but read the functions from an iterable."""
433437
return _compose_left(iterable)
434438

435-
436-
# currying versions
437439
def composerc(*fs):
438440
"""Like composer, but curry each function before composing.
439441
@@ -445,17 +447,19 @@ def composerc(*fs):
445447
add = lambda x, y: x + y
446448
assert curry(mymap, add, ll(1, 2, 3), ll(4, 5, 6)) == ll(5, 7, 9)
447449
"""
448-
return composeric(fs)
449-
def composeric(iterable):
450-
"""Like composeri, but curry each function before composing."""
451-
return composeri(map(curry, iterable))
450+
return composerci(fs)
451+
452452
def composelc(*fs):
453453
"""Like composel, but curry each function before composing."""
454-
return composelic(fs)
455-
def composelic(iterable):
456-
"""Like composeli, but curry each function before composing."""
457-
return composeli(map(curry, iterable))
454+
return composelci(fs)
455+
456+
def composerci(iterable):
457+
"""Like composerc, but read the functions from an iterable."""
458+
return composeri(map(curry, iterable))
458459

460+
def composelci(iterable):
461+
"""Like composelc, but read the functions from an iterable."""
462+
return composeli(map(curry, iterable))
459463

460464
# Helpers to insert one-in-one-out functions into multi-arg compose chains
461465
def tokth(k, f):
@@ -485,13 +489,10 @@ def to1st(f):
485489
486490
Example::
487491
488-
nil = ()
489-
def cons(x, l): # elt, acc
490-
return (x,) + l
491492
def mymap_one(f, sequence):
492493
f_then_cons = composer(cons, to1st(f)) # args: elt, acc
493494
return foldr(f_then_cons, nil, sequence)
494-
double = lambda x: 2*x
495+
double = lambda x: 2 * x
495496
assert mymap_one(double, (1, 2, 3)) == (2, 4, 6)
496497
"""
497498
return tokth(0, f) # this is just a partial() but we want to provide a docstring.

unpythonic/it.py

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -267,22 +267,11 @@ def flatten_in(iterable, pred=None):
267267
def test():
268268
from operator import add, mul, itemgetter
269269
from functools import partial
270+
from unpythonic.fun import curry, composer, composerc, composel, to1st, rotate, identity
271+
from unpythonic.llist import cons, nil, ll
270272

271-
import unpythonic.fun
272-
curry = unpythonic.fun.curry
273-
composer = unpythonic.fun.composer
274-
composerc = unpythonic.fun.composerc
275-
composel = unpythonic.fun.composel
276-
to1st = unpythonic.fun.to1st
277-
rotate = unpythonic.fun.rotate
278-
identity = unpythonic.fun.identity
279-
280-
# just a testing hack; for a "real" cons, see unpythonic.llist.cons
281-
nil = ()
282-
def cons(x, l): # elt, acc
283-
return (x,) + l
284-
assert foldl(cons, nil, (1, 2, 3)) == (3, 2, 1)
285-
assert foldr(cons, nil, (1, 2, 3)) == (1, 2, 3)
273+
assert foldl(cons, nil, ll(1, 2, 3)) == ll(3, 2, 1)
274+
assert foldr(cons, nil, ll(1, 2, 3)) == ll(1, 2, 3)
286275

287276
assert reducel(add, (1, 2, 3)) == 6
288277
assert reducer(add, (1, 2, 3)) == 6
@@ -296,19 +285,19 @@ def mymap_one(f, sequence):
296285
f_then_cons = composer(cons, to1st(f)) # args: elt, acc
297286
return foldr(f_then_cons, nil, sequence)
298287
double = lambda x: 2 * x
299-
assert mymap_one(double, (1, 2, 3)) == (2, 4, 6)
288+
assert mymap_one(double, ll(1, 2, 3)) == ll(2, 4, 6)
300289
def mymap_one2(f, sequence):
301290
f_then_cons = composel(to1st(f), cons) # args: elt, acc
302291
return foldr(f_then_cons, nil, sequence)
303-
assert mymap_one2(double, (1, 2, 3)) == (2, 4, 6)
292+
assert mymap_one2(double, ll(1, 2, 3)) == ll(2, 4, 6)
304293

305294
# point-free-ish style
306295
mymap_one3 = lambda f: partial(foldr, composer(cons, to1st(f)), nil)
307296
doubler = mymap_one3(double)
308-
assert doubler((1, 2, 3)) == (2, 4, 6)
297+
assert doubler(ll(1, 2, 3)) == ll(2, 4, 6)
309298

310299
try:
311-
doubler((1, 2, 3), (4, 5, 6))
300+
doubler(ll(1, 2, 3), ll(4, 5, 6))
312301
except TypeError:
313302
pass
314303
else:
@@ -317,25 +306,25 @@ def mymap_one2(f, sequence):
317306
# minimum arity of fold functions is 3, to allow use with curry:
318307
mymap_one4 = lambda f: curry(foldr, composer(cons, to1st(f)), nil)
319308
doubler = mymap_one4(double)
320-
assert doubler((1, 2, 3)) == (2, 4, 6)
309+
assert doubler(ll(1, 2, 3)) == ll(2, 4, 6)
321310

322311
# curry supports passing through on the right any args over the max arity.
323312
assert curry(double, 2, "foo") == (4, "foo") # arity of double is 1
324313

325314
# In passthrough, if an intermediate result is a callable,
326315
# it is invoked on the remaining positional args:
327-
assert curry(mymap_one4, double, (1, 2, 3)) == (2, 4, 6)
316+
assert curry(mymap_one4, double, ll(1, 2, 3)) == ll(2, 4, 6)
328317

329318
# This also works; curried f takes one argument and the second one is passed
330319
# through on the right; this two-tuple then ends up as the arguments to cons.
331320
mymap_one5 = lambda f: curry(foldr, composer(cons, curry(f)), nil)
332-
assert curry(mymap_one5, double, (1, 2, 3)) == (2, 4, 6)
321+
assert curry(mymap_one5, double, ll(1, 2, 3)) == ll(2, 4, 6)
333322

334323
# Finally, we can drop the inner curry by using a currying compose.
335324
# This is as close to "(define (map f) (foldr (compose cons f) empty)"
336325
# (#lang spicy) as we're gonna get in Python.
337326
mymap = lambda f: curry(foldr, composerc(cons, f), nil)
338-
assert curry(mymap, double, (1, 2, 3)) == (2, 4, 6)
327+
assert curry(mymap, double, ll(1, 2, 3)) == ll(2, 4, 6)
339328

340329
# The currying has actually made it not just map one, but general map that
341330
# accepts multiple input sequences.
@@ -344,21 +333,23 @@ def mymap_one2(f, sequence):
344333
# argument, is passed through on the right. The output from the processing
345334
# function - one new item - and acc then become a two-tuple, which gets
346335
# passed into cons.
347-
assert curry(mymap, lambda x, y: x + y, (1, 2, 3), (2, 4, 6)) == (3, 6, 9)
336+
add = lambda x, y: x + y
337+
assert curry(mymap, add, ll(1, 2, 3), ll(2, 4, 6)) == ll(3, 6, 9)
348338

349339
reverse_one = curry(foldl, cons, nil)
350-
assert reverse_one((1, 2, 3)) == (3, 2, 1)
340+
assert reverse_one(ll(1, 2, 3)) == ll(3, 2, 1)
351341

352-
append_two = lambda a, b: foldr(cons, b, a)
353-
assert append_two((1, 2, 3), (4, 5, 6)) == (1, 2, 3, 4, 5, 6)
342+
append_two = lambda a, b: foldr(cons, b, a) # a, b: linked lists
343+
assert append_two(ll(1, 2, 3), ll(4, 5, 6)) == ll(1, 2, 3, 4, 5, 6)
354344

345+
# see upythonic.llist.lappend
355346
append_many = lambda *lsts: foldr(append_two, nil, lsts)
356-
assert append_many((1, 2), (3, 4), (5, 6)) == (1, 2, 3, 4, 5, 6)
347+
assert append_many(ll(1, 2), ll(3, 4), ll(5, 6)) == ll(1, 2, 3, 4, 5, 6)
357348

358349
mysum = curry(foldl, add, 0)
359350
myprod = curry(foldl, mul, 1)
360-
a = (1, 2)
361-
b = (3, 4)
351+
a = ll(1, 2)
352+
b = ll(3, 4)
362353
assert mysum(append_two(a, b)) == 10
363354
assert myprod(b) == 12
364355

unpythonic/llist.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from collections.abc import Sequence
1010
from itertools import zip_longest
1111

12-
from unpythonic.fun import composeri1
12+
from unpythonic.fun import composer1i
1313
from unpythonic.it import foldr, foldl
1414

1515
# explicit list better for tooling support
@@ -210,7 +210,7 @@ def _typecheck(x):
210210
def _build_accessor(name):
211211
spec = name[1:-1]
212212
f = {'a': _car, 'd': _cdr}
213-
return composeri1(f[char] for char in spec)
213+
return composer1i(f[char] for char in spec)
214214

215215
def car(x):
216216
"""Return the first half of a cons cell.""" # no autobuild, we want a docstring.

0 commit comments

Comments
 (0)