Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add built-in to combine unary functions into a function that applies each function to the corresponding argument #807

Closed
evhub opened this issue Nov 27, 2023 · 7 comments

Comments

@evhub
Copy link
Owner

evhub commented Nov 27, 2023

Should be equivalent to a pickleable version of

def apply(*funcs, map_using=map) = (*args) => map_using(call, funcs, args, strict=True)
@evhub evhub added the feature label Nov 27, 2023
@evhub evhub added this to the v3.1.0 milestone Nov 27, 2023
@evhub evhub changed the title Add a built-in that combines unary function into one function that applies each function to the corresponding argument Add a built-in that combines unary functions into one function that applies each function to the corresponding argument Nov 27, 2023
@evhub evhub changed the title Add a built-in that combines unary functions into one function that applies each function to the corresponding argument Add built-in to combine unary functions into a function that applies each function to the corresponding argument Nov 27, 2023
@evhub
Copy link
Owner Author

evhub commented Nov 27, 2023

We should also add

apply.using_processes = apply$(map_using=process_map)
apply.using_threads = apply$(map_using=thread_map)
apply.using_async = apply$(map_using=async_map)

@evhub
Copy link
Owner Author

evhub commented Nov 27, 2023

Initial implementation for header:

class apply(_coconut_base_callable):
	"""Given unary functions, create a new function that applies each function to its corresponding argument.

	Thus, apply((.+1), (.*2)) is equivalent to (x, y) -> (x + 1, y * 2).

	Effectively equivalent to:
        def apply(*funcs, map_using=map) =
            (*args) => map_using(call, funcs, args, strict=True)
	"""
    __slots__ = ("funcs", "map_using")
    def __init__(self, *funcs, **kwargs):
        self.funcs = funcs
        self.map_using = kwargs.pop("map_using", None)
        if kwargs:
            raise _coconut.TypeError("apply() got unexpected keyword arguments " + _coconut.repr(kwargs))
    def __reduce__(self):
        return (self.__class__, self.funcs, {lbrace}"map_using": self.map_using{rbrace})
    def __repr__(self):
        return "apply(" + ", ".join(_coconut.repr(f) for f in self.funcs) + (", map_using=" + _coconut.repr(self.map_using) if self.map_using is not None else "") + ")"
    def __call__(self, *args):
        return ({_coconut_}map if self.map_using is None else self.map_using)({_coconut_}call, self.funcs, self.args, strict=True)

@evhub
Copy link
Owner Author

evhub commented Nov 28, 2023

Alternatively, we could make something closer to lift like

def comp(func) = (*func_args, **func_kwargs) => (*args, **kwargs) => (
    func(
        *map(call, func_args, args, strict=True),
        **{k: func_kwargs[k](kwargs[k]) for k in func_kwargs.keys() | kwargs.keys()},
    )
)

@evhub
Copy link
Owner Author

evhub commented Nov 28, 2023

To encourage piping with branching, we should also add usage of

branch = lift(,)
branched = comp(,)

to the documentation.

@evhub
Copy link
Owner Author

evhub commented Nov 29, 2023

For symmetry with lift, we could name it:

  • nlift
  • multi_lift
  • lift_args
  • lift_apart

Note that the usage is as the D2 combinator.

@evhub evhub added the resolved label Dec 3, 2023
@evhub
Copy link
Owner Author

evhub commented Dec 3, 2023

Added as lift_apart.

@evhub evhub closed this as completed Dec 3, 2023
evhub added a commit that referenced this issue Dec 3, 2023
@evhub
Copy link
Owner Author

evhub commented Dec 5, 2023

Maybe lift_args is a better name than lift_apart, actually.

@evhub evhub reopened this Dec 5, 2023
@evhub evhub closed this as completed Jan 18, 2024
@evhub evhub mentioned this issue Mar 1, 2024
evhub added a commit that referenced this issue Mar 2, 2024
See Coconut's
[documentation](http://coconut.readthedocs.io/en/develop/DOCS.html) for
more information on all of the features listed below.

Language changes:
* #814: Changes to statement lambda scoping rules, including capturing
names introduced in the surrounding expression.
* #618: Changes to handling of pattern-matching function defaults
including support for e.g. `match def f(x, y=x) = (x, y)`.
* #809: New array concatenation implicit partials (e.g. `[. ; a]`).
* #823: New `(x := .)` implicit partial syntax (only available in
pipes).
* #807: New `lift_apart` built-in combinator.
* #813: New `(if)` operator function.
* #826 (thanks @JayXon!): Better universalization and `fmap` support for
`bytes` and `bytearray`.
* #816: Support for `xarray` to match existing `numpy`/`pandas` support.
* #817: New `to` argument to `all_equal`.
* #821 (thanks @GolfingSuccess!): Expanded implicit function application
syntax to support string literal methods.

Compiler changes:
* #799: `coconut-run` and `coconut --run` now work on packages rather
than just files.
* #812: Better formatting of Coconut exceptions.

Bugfixes:
* #810: Fixed an issue compiling certain syntax constructs in the
Coconut Jupyter kernel.
* #818, #825 (thanks @kg583, @dokutan!): Fixed parsing of different
Unicode line break characters.
* #822 (thanks @JayXon!): Fixed parsing of Unicode backward pipe
operators.
* #819, #820 (thanks @kg583!): Fixed some incompatibilities between
Python and Coconut syntax.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant