Есть ли имя для функции, которая возвращает позиционно-расширяющуюся версию своего аргумента?
Рассматривать 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?".