back

by elesiuta·3y ago·view on hn ↗
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=_))