Skip to content

Commit c3b0273

Browse files
committed
Improve partials
Resolves #797.
1 parent a99a76d commit c3b0273

File tree

9 files changed

+42
-26
lines changed

9 files changed

+42
-26
lines changed

DOCS.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,8 @@ def new_f(x, *args, **kwargs):
628628
return f(*args, **kwargs)
629629
```
630630

631+
Unlike `functools.partial`, Coconut's partial application will preserve the `__name__` of the wrapped function.
632+
631633
##### Rationale
632634

633635
Partial application, or currying, is a mainstay of functional programming, and for good reason: it allows the dynamic customization of functions to fit the needs of where they are being used. Partial application allows a new function to be created out of an old function with some of its arguments pre-specified.
@@ -4262,7 +4264,11 @@ If _map_using_ is passed, calculates `key_func` and `value_func` by mapping them
42624264

42634265
##### **mapreduce.using_processes**(_key\_value\_func_, _iterable_, \*, _reduce\_func_=`None`, _collect\_in_=`None`, _ordered_=`False`, _chunksize_=`1`, _max\_workers_=`None`)
42644266

4265-
These shortcut methods call `collectby`/`mapreduce` with `map_using` set to [`process_map`](#process_map)/[`thread_map`](#thread_map), properly managed using the `.multiple_sequential_calls` method and the `stream=True` argument of [`process_map`](#process_map)/[`thread_map`](#thread_map). `reduce_func` will be called as soon as results arrive, and by default in whatever order they arrive in (to enforce the original order, pass _ordered_=`True`). Note that, for very long iterables, it is highly recommended to pass a value other than the default `1` for _chunksize_.
4267+
These shortcut methods call `collectby`/`mapreduce` with `map_using` set to [`process_map`](#process_map)/[`thread_map`](#thread_map), properly managed using the `.multiple_sequential_calls` method and the `stream=True` argument of [`process_map`](#process_map)/[`thread_map`](#thread_map). `reduce_func` will be called as soon as results arrive, and by default in whatever order they arrive in (to enforce the original order, pass _ordered_=`True`).
4268+
4269+
To make multiple sequential calls to `collectby.using_threads()`/`mapreduce.using_threads()`, manage them using `thread_map.multiple_sequential_calls()`. Similarly, use `process_map.multiple_sequential_calls()` to manage `.using_processes()`.
4270+
4271+
Note that, for very long iterables, it is highly recommended to pass a value other than the default `1` for _chunksize_.
42664272

42674273
As an example, `mapreduce.using_processes` is effectively equivalent to:
42684274
```coconut

__coconut__/__init__.pyi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ tee = _coconut.itertools.tee
208208
starmap = _coconut.itertools.starmap
209209
cartesian_product = _coconut.itertools.product
210210

211+
_coconut_partial = _coconut.functools.partial
211212
_coconut_tee = tee
212213
_coconut_starmap = starmap
213214
_coconut_cartesian_product = cartesian_product
@@ -644,7 +645,8 @@ def _coconut_mark_as_match(func: _Tfunc) -> _Tfunc:
644645
return func
645646

646647

647-
class _coconut_partial(_t.Generic[_T]):
648+
class _coconut_complex_partial(_t.Generic[_T]):
649+
func: _t.Callable[..., _T] = ...
648650
args: _Tuple = ...
649651
required_nargs: int = ...
650652
keywords: _t.Dict[_t.Text, _t.Any] = ...
@@ -658,6 +660,7 @@ class _coconut_partial(_t.Generic[_T]):
658660
**kwargs: _t.Any,
659661
) -> None: ...
660662
def __call__(self, *args: _t.Any, **kwargs: _t.Any) -> _T: ...
663+
__name__: str | None = ...
661664

662665

663666
@_t.overload

coconut/__coconut__.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
from __coconut__ import *
2-
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_Expected, _coconut_MatchError, _coconut_SupportsAdd, _coconut_SupportsMinus, _coconut_SupportsMul, _coconut_SupportsPow, _coconut_SupportsTruediv, _coconut_SupportsFloordiv, _coconut_SupportsMod, _coconut_SupportsAnd, _coconut_SupportsXor, _coconut_SupportsOr, _coconut_SupportsLshift, _coconut_SupportsRshift, _coconut_SupportsMatmul, _coconut_SupportsInv, _coconut_Expected, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul, _coconut_py_str, _coconut_flatten, _coconut_multiset, _coconut_back_none_pipe, _coconut_back_none_star_pipe, _coconut_back_none_dubstar_pipe, _coconut_forward_none_compose, _coconut_back_none_compose, _coconut_forward_none_star_compose, _coconut_back_none_star_compose, _coconut_forward_none_dubstar_compose, _coconut_back_none_dubstar_compose, _coconut_call_or_coefficient, _coconut_in, _coconut_not_in, _coconut_attritemgetter
2+
from __coconut__ import _coconut_tail_call, _coconut_tco, _coconut_call_set_names, _coconut_handle_cls_kwargs, _coconut_handle_cls_stargs, _namedtuple_of, _coconut, _coconut_Expected, _coconut_MatchError, _coconut_SupportsAdd, _coconut_SupportsMinus, _coconut_SupportsMul, _coconut_SupportsPow, _coconut_SupportsTruediv, _coconut_SupportsFloordiv, _coconut_SupportsMod, _coconut_SupportsAnd, _coconut_SupportsXor, _coconut_SupportsOr, _coconut_SupportsLshift, _coconut_SupportsRshift, _coconut_SupportsMatmul, _coconut_SupportsInv, _coconut_Expected, _coconut_MatchError, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_complex_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul, _coconut_py_str, _coconut_flatten, _coconut_multiset, _coconut_back_none_pipe, _coconut_back_none_star_pipe, _coconut_back_none_dubstar_pipe, _coconut_forward_none_compose, _coconut_back_none_compose, _coconut_forward_none_star_compose, _coconut_back_none_star_compose, _coconut_forward_none_dubstar_compose, _coconut_back_none_dubstar_compose, _coconut_call_or_coefficient, _coconut_in, _coconut_not_in, _coconut_attritemgetter

coconut/compiler/compiler.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2797,7 +2797,7 @@ def pipe_handle(self, original, loc, tokens, **kwargs):
27972797
return expr
27982798
elif name == "partial":
27992799
self.internal_assert(len(split_item) == 3, original, loc)
2800-
return "_coconut.functools.partial(" + join_args(split_item) + ")"
2800+
return "_coconut_partial(" + join_args(split_item) + ")"
28012801
elif name == "attrgetter":
28022802
return attrgetter_atom_handle(loc, item)
28032803
elif name == "itemgetter":
@@ -2891,14 +2891,14 @@ def item_handle(self, original, loc, tokens):
28912891
out += trailer
28922892
elif len(trailer) == 1:
28932893
if trailer[0] == "$[]":
2894-
out = "_coconut.functools.partial(_coconut_iter_getitem, " + out + ")"
2894+
out = "_coconut_partial(_coconut_iter_getitem, " + out + ")"
28952895
elif trailer[0] == "$":
2896-
out = "_coconut.functools.partial(_coconut.functools.partial, " + out + ")"
2896+
out = "_coconut_partial(_coconut_partial, " + out + ")"
28972897
elif trailer[0] == "[]":
2898-
out = "_coconut.functools.partial(_coconut.operator.getitem, " + out + ")"
2898+
out = "_coconut_partial(_coconut.operator.getitem, " + out + ")"
28992899
elif trailer[0] == ".":
29002900
self.strict_err_or_warn("'obj.' as a shorthand for 'getattr$(obj)' is deprecated (just use the getattr partial)", original, loc)
2901-
out = "_coconut.functools.partial(_coconut.getattr, " + out + ")"
2901+
out = "_coconut_partial(_coconut.getattr, " + out + ")"
29022902
elif trailer[0] == "type:[]":
29032903
out = "_coconut.typing.Sequence[" + out + "]"
29042904
elif trailer[0] == "type:$[]":
@@ -2931,7 +2931,7 @@ def item_handle(self, original, loc, tokens):
29312931
args = trailer[1][1:-1]
29322932
if not args:
29332933
raise CoconutDeferredSyntaxError("a partial application argument is required", loc)
2934-
out = "_coconut.functools.partial(" + out + ", " + args + ")"
2934+
out = "_coconut_partial(" + out + ", " + args + ")"
29352935
elif trailer[0] == "$[":
29362936
out = "_coconut_iter_getitem(" + out + ", " + trailer[1] + ")"
29372937
elif trailer[0] == "$(?":
@@ -2959,7 +2959,7 @@ def item_handle(self, original, loc, tokens):
29592959
raise CoconutInternalException("no question mark in question mark partial", trailer[1])
29602960
elif argdict_pairs or pos_kwargs or extra_args_str:
29612961
out = (
2962-
"_coconut_partial("
2962+
"_coconut_complex_partial("
29632963
+ out
29642964
+ ", {" + ", ".join(argdict_pairs) + "}"
29652965
+ ", " + str(len(pos_args))

coconut/compiler/grammar.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ def itemgetter_handle(tokens):
447447
if op == "[":
448448
return "_coconut.operator.itemgetter((" + args + "))"
449449
elif op == "$[":
450-
return "_coconut.functools.partial(_coconut_iter_getitem, index=(" + args + "))"
450+
return "_coconut_partial(_coconut_iter_getitem, index=(" + args + "))"
451451
else:
452452
raise CoconutInternalException("invalid implicit itemgetter type", op)
453453
else:
@@ -540,10 +540,10 @@ def partial_op_item_handle(tokens):
540540
tok_grp, = tokens
541541
if "left partial" in tok_grp:
542542
arg, op = tok_grp
543-
return "_coconut.functools.partial(" + op + ", " + arg + ")"
543+
return "_coconut_partial(" + op + ", " + arg + ")"
544544
elif "right partial" in tok_grp:
545545
op, arg = tok_grp
546-
return "_coconut_partial(" + op + ", {1: " + arg + "}, 2, ())"
546+
return "_coconut_complex_partial(" + op + ", {1: " + arg + "}, 2, ())"
547547
else:
548548
raise CoconutInternalException("invalid operator function implicit partial token group", tok_grp)
549549

@@ -1013,7 +1013,7 @@ class Grammar(object):
10131013
| fixto(dubquestion, "_coconut_none_coalesce")
10141014
| fixto(dot, "_coconut.getattr")
10151015
| fixto(unsafe_dubcolon, "_coconut.itertools.chain")
1016-
| fixto(dollar, "_coconut.functools.partial")
1016+
| fixto(dollar, "_coconut_partial")
10171017
| fixto(exp_dubstar, "_coconut.operator.pow")
10181018
| fixto(mul_star, "_coconut.operator.mul")
10191019
| fixto(div_dubslash, "_coconut.operator.floordiv")

coconut/compiler/header.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ def pattern_prepender(func):
314314
return pattern_prepender
315315
def datamaker(data_type):
316316
"""DEPRECATED: use makedata instead."""
317-
return _coconut.functools.partial(makedata, data_type)
317+
return _coconut_partial(makedata, data_type)
318318
of, parallel_map, concurrent_map, recursive_iterator = call, process_map, thread_map, recursive_generator
319319
'''
320320
if not strict else
@@ -599,7 +599,7 @@ async def __anext__(self):
599599
# (extra_format_dict is to keep indentation levels matching)
600600
extra_format_dict = dict(
601601
# when anything is added to this list it must also be added to *both* __coconut__ stub files
602-
underscore_imports="{tco_comma}{call_set_names_comma}{handle_cls_args_comma}_namedtuple_of, _coconut, _coconut_Expected, _coconut_MatchError, _coconut_SupportsAdd, _coconut_SupportsMinus, _coconut_SupportsMul, _coconut_SupportsPow, _coconut_SupportsTruediv, _coconut_SupportsFloordiv, _coconut_SupportsMod, _coconut_SupportsAnd, _coconut_SupportsXor, _coconut_SupportsOr, _coconut_SupportsLshift, _coconut_SupportsRshift, _coconut_SupportsMatmul, _coconut_SupportsInv, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul, _coconut_py_str, _coconut_flatten, _coconut_multiset, _coconut_back_none_pipe, _coconut_back_none_star_pipe, _coconut_back_none_dubstar_pipe, _coconut_forward_none_compose, _coconut_back_none_compose, _coconut_forward_none_star_compose, _coconut_back_none_star_compose, _coconut_forward_none_dubstar_compose, _coconut_back_none_dubstar_compose, _coconut_call_or_coefficient, _coconut_in, _coconut_not_in, _coconut_attritemgetter".format(**format_dict),
602+
underscore_imports="{tco_comma}{call_set_names_comma}{handle_cls_args_comma}_namedtuple_of, _coconut, _coconut_Expected, _coconut_MatchError, _coconut_SupportsAdd, _coconut_SupportsMinus, _coconut_SupportsMul, _coconut_SupportsPow, _coconut_SupportsTruediv, _coconut_SupportsFloordiv, _coconut_SupportsMod, _coconut_SupportsAnd, _coconut_SupportsXor, _coconut_SupportsOr, _coconut_SupportsLshift, _coconut_SupportsRshift, _coconut_SupportsMatmul, _coconut_SupportsInv, _coconut_iter_getitem, _coconut_base_compose, _coconut_forward_compose, _coconut_back_compose, _coconut_forward_star_compose, _coconut_back_star_compose, _coconut_forward_dubstar_compose, _coconut_back_dubstar_compose, _coconut_pipe, _coconut_star_pipe, _coconut_dubstar_pipe, _coconut_back_pipe, _coconut_back_star_pipe, _coconut_back_dubstar_pipe, _coconut_none_pipe, _coconut_none_star_pipe, _coconut_none_dubstar_pipe, _coconut_bool_and, _coconut_bool_or, _coconut_none_coalesce, _coconut_minus, _coconut_map, _coconut_partial, _coconut_complex_partial, _coconut_get_function_match_error, _coconut_base_pattern_func, _coconut_addpattern, _coconut_sentinel, _coconut_assert, _coconut_raise, _coconut_mark_as_match, _coconut_reiterable, _coconut_self_match_types, _coconut_dict_merge, _coconut_exec, _coconut_comma_op, _coconut_multi_dim_arr, _coconut_mk_anon_namedtuple, _coconut_matmul, _coconut_py_str, _coconut_flatten, _coconut_multiset, _coconut_back_none_pipe, _coconut_back_none_star_pipe, _coconut_back_none_dubstar_pipe, _coconut_forward_none_compose, _coconut_back_none_compose, _coconut_forward_none_star_compose, _coconut_back_none_star_compose, _coconut_forward_none_dubstar_compose, _coconut_back_none_dubstar_compose, _coconut_call_or_coefficient, _coconut_in, _coconut_not_in, _coconut_attritemgetter".format(**format_dict),
603603
import_typing=pycondition(
604604
(3, 5),
605605
if_ge='''

0 commit comments

Comments
 (0)