Skip to content

Commit 1aa6f9d

Browse files
committed
Resolve #19: add curry-friendly thin wrapper unpythonic.it.map.
1 parent 470a06b commit 1aa6f9d

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

unpythonic/it.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
``itertools`` recipes.
1111
"""
1212

13-
__all__ = ["rev", "map_longest",
13+
__all__ = ["rev", "map", "map_longest",
1414
"rmap", "rzip", "rmap_longest", "rzip_longest",
1515
"mapr", "zipr", "mapr_longest", "zipr_longest",
1616
"flatmap",
@@ -27,6 +27,7 @@
2727
"window", "chunked",
2828
"within", "fixpoint"]
2929

30+
from builtins import map as stdlib_map
3031
from operator import itemgetter
3132
from itertools import tee, islice, zip_longest, starmap, chain, filterfalse, groupby, takewhile
3233
from collections import deque
@@ -51,6 +52,22 @@ def rev(iterable):
5152
except TypeError:
5253
return reversed(tuple(iterable))
5354

55+
def map(function, iterable0, *iterables):
56+
"""Curry-friendly map.
57+
58+
Thin wrapper around Python's builtin ``map``, making it mandatory to
59+
provide at least one iterable, so we may say things such as::
60+
61+
from unpythonic import map, curry
62+
oneplus = lambda x: 1 + x # noqa: E731
63+
64+
add_one = curry(map, oneplus)
65+
66+
assert tuple(add_one(range(5))) == tuple(range(1, 6))
67+
68+
"""
69+
return stdlib_map(function, iterable0, *iterables)
70+
5471
# When completing an existing set of functions (map, zip, zip_longest),
5572
# consistency wins over curry-friendliness.
5673
def map_longest(func, *iterables, fillvalue=None):

unpythonic/test/test_it.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from collections import deque
77
from math import cos, sqrt
88

9-
from ..it import mapr, rmap, zipr, rzip, \
9+
from ..it import map, mapr, rmap, zipr, rzip, \
1010
map_longest, mapr_longest, rmap_longest, \
1111
zip_longest, zipr_longest, rzip_longest, \
1212
first, second, nth, last, lastn, \
@@ -21,7 +21,7 @@
2121
window, chunked, \
2222
within, fixpoint
2323

24-
from ..fun import composel, identity
24+
from ..fun import composel, identity, curry
2525
from ..gmemo import imemoize, gmemoize
2626
from ..mathseq import s
2727
from ..misc import Popper, ulp
@@ -31,9 +31,15 @@ def noneadd(a, b):
3131
if all(x is not None for x in (a, b)):
3232
return a + b
3333

34+
# Our map is a thin wrapper that makes it mandatory to provide at least one iterable,
35+
# so we can easily curry it with just the function to be applied.
36+
oneplus = lambda x: 1 + x # noqa: E731
37+
add_one = curry(map, oneplus)
38+
assert tuple(add_one(range(5))) == tuple(range(1, 6))
39+
3440
# Adding the missing batteries to the algebra of map and zip.
3541
# Note Python's (and Racket's) map is like Haskell's zipWith, but for n inputs.
36-
assert tuple(map(add, (1, 2), (3, 4))) == (4, 6) # builtin
42+
assert tuple(map(add, (1, 2), (3, 4))) == (4, 6) # builtin (or ours, doesn't matter)
3743
assert tuple(mapr(add, (1, 2), (3, 4))) == (6, 4)
3844
assert tuple(rmap(add, (1, 2), (3, 4))) == (6, 4)
3945
assert tuple(zip((1, 2, 3), (4, 5, 6), (7, 8))) == ((1, 4, 7), (2, 5, 8)) # builtin

0 commit comments

Comments
 (0)