Как вывести функцию в заданную позицию аргумента - PullRequest
1 голос
/ 10 июля 2019

Можно ли карри функции в пользовательской n-й позиции? Частичная функция Functool может обрабатывать частичные вычисления нескольких аргументов,

from functools import partial

def f(x,y,z):
    return [x,y,z]

Тогда

partial(f,1)(2,3)

[1,2,3]

и

partial(f,1,2)(3)

[1,2,3]

Возможно ли карри в заданной позиции аргумента?

curry_at(f,n)

Так что

curry_at(f,2)(1,3)(2)

1024 * дает *

[1,2,3]

где, я думаю, для согласованности с возможными * arg и ** kwarg, n должно быть не больше числа обычных аргументов?

Существует ли метод для перечисления аргументов для разделения аргументов префикса и постфикса для n-го слота?

Ответы [ 2 ]

1 голос
/ 10 июля 2019

Не рекомендуется рекомендовать создание таких функций, как это, но в этом случае, я думаю, лучше иметь статические определения с небольшим дублированием, а не полагаться на динамическую функцию, сложное поведение которой трудно проверить -

def apply_at_1 (f, *a, **kw):
  return lambda x, *a2, **kw2: \
    f(x, *a, *a2, **kw, **kw2)

def apply_at_2 (f, *a, **kw):
  return lambda x, y, *a2, **kw2: \
    f(x, y, *a, *a2, **kw, **kw2)

def apply_at_3 (f, *a, **kw):
  return lambda x, y, z, *a2, **kw2: \
    f(x, y, z, *a, *a2, **kw, **kw2)

def dummy (a, b, c, d, *more):
  print (a, b, c, d, *more)

apply_at_1(dummy, 2, 3, 4)(1, 5, 6, 7, 8)
# 1 2 3 4 5 6 7 8

apply_at_2(dummy, 3, 4, 5)(1, 2, 6, 7, 8)
# 1 2 3 4 5 6 7 8

apply_at_3(dummy, 4, 5, 6)(1, 2, 3, 7, 8)
# 1 2 3 4 5 6 7 8

Конечно, динамическая функция позволяет вам применять аргумент в любой позиции, но если вам нужно применить аргумент в четвертой позиции (5-й аргумент), возможно, пришло время рассмотреть рефакторинг. В этом случае я думаю, что лучше установить разумный предел, а затем дисциплинировать себя.

Другие функциональные языки делают схожие вещи по типу ввода. Рассмотрим liftA2, liftA3, liftA4 и т.д. у Хаскелла или List.map, List.map2, List.map3, List.map4, ...

вяза

Иногда поцеловать просто проще.


Вот версия partial с поддержкой подстановочных знаков, __ -

def __ ():
  return None;

def partial (f, *a):
  def combine (a, b):
    if not a:
      return b
    elif a[0] is __:
      return (b[0], *combine(a[1:], b[1:]))
    else:
      return (a[0], *combine(a[1:], b))
  return lambda *b: f(*combine(a,b))

def dummy (a, b, c, d, *more):
  print (a, b, c, d, *more)

partial(dummy, 1, __, __, 4)(2, 3, 5, 6, 7, 8) 
# 1 2 3 4 5 6 7 8

partial(dummy, __, __, 3, __, __, 6, 7, 8)(1, 2, 4, 5)
# 1 2 3 4 5 6 7 8
0 голосов
/ 10 июля 2019

Я попробовал обходной путь, используя индекс и цикл for, надеюсь, это поможет:

from functools import partial

def curry_at(funtion,parameter,index,*args):
  h = funtion
  index-=1
  ls = list(args)
  ls.insert(index,parameter)
  for arg in ls:
      h = partial(h,arg)
  return h()

a = curry_at(f,'a',2,'c','d')

b = curry_at(f,2,2,1,3)

a

['c', 'a', 'd']

b

[1,2,3]

...