Есть ли имя для функции, которая возвращает позиционно-расширяющуюся версию своего аргумента?

Рассматривать splatter в этом коде Python:

def splatter(fn):
    return lambda (args): fn(*args)

def add(a, b):
    return a + b

list1 = [1, 2, 3]
list2 = [4, 5, 6]
print map(splatter(add), zip(list1, list2))

Отображение n-арной функции на n сжатых последовательностей кажется достаточно распространенной операцией, так что для этого уже может быть имя, но я понятия не имею, где я мог бы это найти. Это смутно вызывает карри, и, похоже, есть другие связанные с аргументами HOF, о которых я никогда не слышал. Кто-нибудь знает, если это "хорошо известная" функция? Обсуждая это, я в настоящее время застрял с неловким языком, использованным в заголовке вопроса.

редактировать

Вау, Питон map делает это автоматически. Ты можешь написать:

map(add, list1, list2)

И это будет делать правильно, избавляя вас от проблем splatterв вашей функции. Единственная разница в том, что zip возвращает список, длина которого равна длине его самого короткого аргумента, тогда как map расширяет более короткие списки None,

2 ответа

Решение

Я случайно увидел это в своем списке "Заданных вопросов" и был удивлен, что теперь я знаю ответ.

Есть две интерпретации функции, которую я спросил.

Первым было мое намерение: взять функцию, которая принимает фиксированное количество аргументов, и преобразовать ее в функцию, которая принимает эти аргументы в виде списка или кортежа фиксированного размера. В Haskell вызывается функция, которая выполняет эту операцию uncurry,

uncurry :: (a -> b -> c) -> ((a, b) -> c)

(Дополнительные символы для ясности.)

Легко представить расширение этого для функций более чем двух аргументов, хотя это не может быть выражено в Haskell. Но uncurry3, uncurry4и т. д. не будет не к месту.

Так что я был прав, что это "смутно вызывает карри", поскольку на самом деле все наоборот.


Вторая интерпретация состоит в том, чтобы взять функцию, которая принимает намеренно переменное число аргументов, и вернуть функцию, которая принимает один список.

Так как splat это настолько странно, как синтаксическая конструкция в Python, об этом трудно рассуждать.

Но если мы представим, скажем, JavaScript, который имеет первоклассную именованную функцию для "splatting:"

varFn.apply(null, args)

var splatter = function(f) {
    return function(arg) {
        return f.apply(null, arg);
    };
};

Тогда мы могли бы перефразировать это как просто частичное применениеapply"функция:

var splatter = function(f) {
    return Function.prototype.apply.bind(f, null);
};

Или используя Underscore'spartialмы можем придумать бессмысленное определение:

var splatter = _.partial(Function.prototype.bind.bind(Function.prototype.apply), _, null)

Да, это кошмар.

(Альтернатива _.partial требует определения какого-то swap помощник и выйдет еще менее читабельным, я думаю.)

Поэтому я думаю, что название этой операции - это просто "частичное применение apply", или в случае с Python это почти похоже на раздел оператора splat - если splat был" реальным "оператором.


Но конкретная комбинация uncurry, zip, а также map в оригинальном вопросе точно zipWith Крис указал. Фактически, HLint по умолчанию включает в себя правило, чтобы заменить эту сложную конструкцию одним вызовом zipWith,


Надеюсь, это прояснит ситуацию, мимо Иана.

Я думаю zipWith это функция, которую вы ищете (это имя, по крайней мере, используется в Haskell). Это даже немного более общее. В хаскеле zipWith определяется следующим образом (где первая строка - это просто тип):

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
zipWith _ _      _      = []

И ваш пример будет что-то вроде

zipWith (+) [1, 2, 3] [4, 5, 6]

Поскольку я не очень хорошо знаю Python, я могу указать только на " zipWith аналог в Python?".

Другие вопросы по тегам