是否有函数的名称返回其参数的位置扩展版本?

时间:2012-02-24 22:46:56

标签: higher-order-functions splat

在此Python代码中考虑splatter

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-ary函数映射到n个压缩序列似乎是一个很常见的操作,可能已经有了这个名称,但我不知道我在哪里找到它。它模糊地唤起了人们的讨论,似乎可能还有其他相关的以论证为中心的HOF,我从未听说过。有谁知道这是否是一个“众所周知”的功能?在讨论时,我目前仍然坚持使用问题标题中使用的笨拙语言。

修改

哇,Python的map会自动执行此操作。你可以写:

map(add, list1, list2)

它会做正确的事情,为您省去splatter功能的麻烦。唯一的区别是zip返回一个列表,其长度是其最短参数的长度,而map使用None扩展更短的列表。

2 个答案:

答案 0 :(得分:1)

我认为zipWith是您正在搜索的函数(此名称至少在Haskell中使用)。它甚至更普遍。在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 analogue in Python?”。

答案 1 :(得分:0)

我在“问题问题”列表中随机看到了这一点,并对我现在知道答案感到惊讶。

我问过这个函数有两种解释。

第一个是我的意图:采用一个函数,它接受固定数量的参数并将其转换为一个函数,将这些参数作为固定大小的列表或元组。在Haskell中,执行此操作的函数称为uncurry

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

(为了清楚起见,额外的parens。)

很容易想象将它扩展到两个以上参数的函数,尽管它不能在Haskell中表达。但uncurry3uncurry4等不会不合适。

所以我说得对,“模糊地引起了讨论”,因为它恰恰相反。

第二种解释是采用一个函数,该函数采用有意数量的可变参数并返回一个带有单个列表的函数。

因为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's partial,我们可以提出无点定义:

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

是的,这是一场噩梦。

_.partial的替代方案需要定义某种swap帮助程序,我认为它的可读性会更低。)

所以我认为这个操作的名称只是“apply的部分应用”,或者在Python的情况下它几乎就像是splat运算符的section - 如果splat是“实际”操作员。

但原始问题中uncurryzipmap的特定组合恰好是zipWithas chris pointed out。实际上,HLint默认includes a rule只需调用zipWith即可替换此复杂构造。

我希望通过伊恩来解决问题。