This sounded like it'd be fun to implement so I took a quick stab at it, it supports unpacking tuples to any number of _ in any position, including with kwargs.
class Placeholder:
def __init__(self) -> None:
pass
_ = Placeholder()
class Arrow:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
if not any(isinstance(arg, Placeholder) for arg in args) and \
not (kwargs and any(isinstance(arg, Placeholder) for arg in kwargs.values())):
return self.func(*args, **kwargs)
else:
placeholder_indices = [i for i, arg in enumerate(args) if isinstance(arg, Placeholder)]
placeholder_kwargs = {k: v for k, v in kwargs.items() if isinstance(v, Placeholder)}
original_kwargs = {k: v for k, v in kwargs.items() if not isinstance(v, Placeholder)}
def new_func(new_args):
assert len(new_args) == len(placeholder_indices) + len(placeholder_kwargs), "ERROR: Wrong number of arguments"
return self.func(
*[new_args[placeholder_indices.index(i)] if i in placeholder_indices else arg for i, arg in enumerate(args)],
**{k: new_args[len(placeholder_indices) + i] for i, k in enumerate(placeholder_kwargs)},
**original_kwargs)
return Arrow(lambda *new_args: new_func(new_args))
def __ror__(self, other):
if isinstance(other, tuple):
return self.func(*other)
return self.func(other)
@Arrow
def add(x, y, z):
return x + y + z
@Arrow
def multiply(x, y):
return x * y
@Arrow
def subtract(x, y):
return x - y
@Arrow
def add_one(x):
return x + 1
print((1, 5) | add(_, 3, _) | add_one | subtract(_, 2) | subtract(50, y=_))