我们称之为(新的?)高阶函数?

时间:2010-09-22 23:03:39

标签: python haskell functional-programming theory higher-order-functions

我试图说出我认为对于更高阶函数的新想法。重要的是,这里是Python和Haskell中的代码来演示这个概念,后面将对此进行解释。

的Python:

>>> def pleat(f, l):
       return map(lambda t: f(*t), zip(l, l[1:]))
>>> pleat(operator.add, [0, 1, 2, 3])
[1, 3, 5]

Haskell中:

Prelude> let pleatWith f xs = zipWith f xs (drop 1 xs)
Prelude> pleatWith (+) [0,1,2,3]
[1,3,5]

正如您可以推断的那样,序列正在迭代,利用相邻元素作为传递函数的参数,将结果投影到新序列中。那么,有没有人看到我们创建的功能?这对功能社区的人来说是否熟悉?如果没有,我们将它命名为什么?

---- Update ----

褶皱获胜!

Prelude> let pleat xs = zip xs (drop 1 xs)
Prelude> pleat [1..4]
[(1,2),(2,3),(3,4)]

Prelude> let pleatWith f xs = zipWith f xs (drop 1 xs)
Prelude> pleatWith (+) [1..4]
[3,5,7]

16 个答案:

答案 0 :(得分:17)

嗯...一个对位。

(`ap` tail) . zipWith

不值得一个名字。

顺便说一句,顺便说一句:

 zip`ap`tail

阿兹特克人的连续数字之神

答案 1 :(得分:6)

由于它类似于“折叠”但不会将列表折叠成单个值,“折痕”怎么样?如果你保持“折痕”,你最终会“折叠”(有点)。

我们可以用烹饪比喻来称之为“捏”,就像捏馅饼的外壳一样,虽然这可能暗示了圆形拉链,其中列表的最后一个元素与第一个元素配对。

def pinch(f, l):
    return map(lambda t: f(*t), zip(l, l[1:]+l[:1]))

(如果您只喜欢“折痕”或“捏”之一,请注意以作为评论。这些是否应该是单独的建议?)

答案 2 :(得分:6)

在Python中,meld等价物位于itertools receipes中并成对调用。

from itertools import starmap, izp, tee

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return izip(a, b)

所以我称之为:

def pairwith(func, seq):
    return starmap(func, pairwise(seq))

我认为这是有道理的,因为当你用身份函数调用它时,它只返回对。

答案 3 :(得分:5)

这是Python的另一个实现,如果l也是一个生成器

import itertools as it

def apply_pairwise(f, l):
    left, right = it.tee(l)
    next(right)
    return it.starmap(f, it.izip(left, right))

我认为apply_pairwise是一个更好的名字

答案 4 :(得分:4)

我确实无法在Python中看到任何编码的名称,这是肯定的。 “合并”很好,但在各种其他情况下都可以说。 “犁”往往未被使用,并提供了一个稳定推动通过土壤线的视觉效果。也许我只是花了太多时间做园艺。

我还扩展了原则,允许接收任意数量参数的函数。

您可能还会考虑:褶皱。它很好地描述了你采用列表的方式(比如一长条布料)并将它们聚集在一起。

import operator

def stagger(l, w):
    if len(l)>=w:
        return [tuple(l[0:w])]+stagger(l[1:], w)
    return []

def pleat(f, l, w=2):
    return map(lambda p: f(*p), stagger(l, w))

print pleat(operator.add, range(10))
print pleat(lambda x, y, z: x*y/z, range(3, 13), 3)
print pleat(lambda x: "~%s~"%(x), range(10), 1)
print pleat(lambda a, b, x, y: a+b==x+y, [3, 2, 4, 1, 5, 0, 9, 9, 0], 4)

答案 5 :(得分:2)

zipWithTailadjacentPairs

答案 6 :(得分:2)

我投票给smearWithsmudgeWith,因为这就像是在整个列表中涂抹/涂抹操作。

答案 7 :(得分:2)

这看起来像红宝石的each_cons

ruby-1.9.2-p0 > (1..10).each_cons(2).to_a

=> [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9], [9, 10]] 

答案 8 :(得分:2)

这让我想起了来自图像处理的卷积。但不确定这在数学上是否正确。

答案 9 :(得分:2)

普通的zip版本的广义变体是我所能想到的window。现在不在ghci终端,但我想window n = take n . tails。然后你的函数是zipWith (\[x,yj -> f x y) . window 2。当f为[a] -> b类型时,这种风格自然会更好。

答案 10 :(得分:2)

在C ++标准模板库中,它被称为adjacent_difference(尽管运算符可以是任何操作,而不仅仅是减法)

答案 11 :(得分:1)

因为似乎没有这个名字我建议'合并'或简单'合并'因为你将相邻的值合并在一起。

所以已经采取合并,所以我现在建议'融合'(或'合并'仍然但可能过于接近'合并')

例如:

meld :: (a -> a -> b) -> [a] -> [b]
meld _ [] = []
meld f xs = zipWith f (init xs) (tail xs)

可以用作:

> meld (+) [1..10]
[3,5,7,9,11,13,15,17,19]
> meld compare "hello world"
[GT,LT,EQ,LT,GT,LT,GT,LT,GT,GT]

第二个例子没有真正意义,但却是一个很酷的例子。

答案 12 :(得分:1)

使用Mathematica

Plus @@@ Partition [{0,1,2,3},2,1] 或者这些更冗长的替代方案中的任何一个

Apply[Plus, Partition[{0, 1, 2, 3}, 2, 1], {1}]
Map[Apply[Plus, #] &, Partition[{0, 1, 2, 3}, 2, 1]]

我在许多语言中使用过并享受过这种高阶函数,但我在Mathematica中最喜欢它;它似乎简洁而灵活,分解为Partition和Apply with levelspec选项。

答案 13 :(得分:1)

我很想把它称为 contour ,因为我已经将它用于音乐软件中的“轮廓”处理 - 当时我把它称为2map或类似的东西。

音乐处理中还有两个特定的'轮廓',一个是粗轮廓 - 音高是上升还是下降。另一个是精致轮廓,其中轮廓向上,向下,向上或向下跳跃,但我似乎无法找到半音差异有多大的参考来进行跳跃。

答案 14 :(得分:1)

好的成语!我只需要在Perl中使用它来确定连续事件之间的时间。这就是我最终的目标。

sub pinch(&@) {
  my ( $f, @list ) = @_;
  no strict "refs";

  use vars qw( $a $b );

  my $caller = caller;
  local( *{$caller . "::a"} ) = \my $a;
  local( *{$caller . "::b"} ) = \my $b;

  my @res;
  for ( my $i = 0; $i < @list - 1; ++$i ) {
    $a = $list[$i];
    $b = $list[$i + 1];
    push( @res, $f->() );
  }
  wantarray ? @res : \@res;
}

print join( ",", pinch { $b - $a } qw( 1 2 3 4 5 6 7 ) ), $/;
# ==> 1,1,1,1,1,1

如果我依赖于 List :: Util ,那么实现可能会更漂亮,但是...... meh!

答案 15 :(得分:0)

BinaryOperate或BinaryMerge