用Python将两个函数配给第三个二进制函数

时间:2018-12-04 18:36:49

标签: python functional-programming operators toolz

我正在慢慢尝试使用Python进行函数编程,并遇到以下问题:

给定两个函数f1f2,我该如何构造一个函数f,以相同的参数“以函数方式”将这两个函数相乘?

没花太多时间从事函数式编程,我确实有一个解决方案

f = lambda x : f1(x) * f2(x)

但是似乎不符合函数式编程的精神。

我的下一个尝试是像这样使用muljuxt运算符

>>> from tools import juxt
>>> from operator import mul
>>> f = mul(juxt(f1,f2))
TypeError: op_mul expected 2 arguments, got 1

尝试用juxt拆分*的元组输出也不起作用:

>>> f = mul(*juxt(f1, f2))
TypeError: mul() argument after * must be an iterable, not juxt

再次使用lambda似乎可行,但是以某种方式破坏了整个目标……

>>> temp  = juxt(f_1, f_2)
>>> f = lambda x : mul(*temp(x))

也许我在这里对Python太过ped脚或太不客气了,但是我觉得我在函数式编程中缺少了一些非常重要或常规的东西。

是否有更实用的方法?

2 个答案:

答案 0 :(得分:4)

TL; DR这种组合是Python和tools模块都不支持的原始操作(从某种意义上说,不能将其分解为其他高阶函数)。您需要自己实施。


您所缺少的(或者更确切地说,Python和tools模块所缺少的)是应用函子的概念。要了解 的含义,首先让我们回顾一下tools模块中的两个功能:

  1. compose使您可以将两个功能链接在一起。也就是说,

    compose(f,g) == lamba x: f(g(x))
    
  2. curry与部分应用有关:演示比解释快:

    curry(f)(x)(y) == f(x, y)
    

    也就是说,curry(f)(x)partial(f, x)基本相同;两者都使用值y来返回值f(x, y)

此外, functor 基本上是一种将函数映射到某个值的方法。您无疑对列表函子很熟悉:

map(f, [a,b,c]) == [f(a), f(b), f(c)]

函数也是 函数,但是我们使用map代替compose。也就是说,将f映射到g会产生compose(f, g)

现在,要将mulf1f2合并为g = lambda x: g(f1(x), f2(x)),似乎composecurry都将是有用的。

lambda x: mul(f1(x), f2(x)) == lambda x: curry(mul)(f1(x))(f2(x))

lambda x: mul(f1(x), f2(x)) == lambda x: compose(curry(mul), f1)(x)(f2(x))

(也就是说,curry使我们可以将另一个函数的两个参数组合在一起。)

但是,从某种意义上讲,合成严格上是 linear 操作;一个功能的输入来自另一个功能的输出。 mulf1的组合创建了一个期望参数的函数,而返回了一个期望相同参数的函数。如何将x从两个表达式的“中间”移出?我们需要一些 神秘功能foo这样

foo(f, g) = lambda x: f(x, g(x))

生成一个函数,该函数将其参数同时传递给 fg,同时还将结果g(x)传递给f。有了这样的功能foo,我们可以编写

lambda x: foo(compose(curry(mul), f1), f2)

并获得我们想要的结果。

这使我们想到了 applicative 函子的概念。它提供了必要的功能foo

def foo(f, g):
   def _(x):
       return f(x, g(x))

结合了我们目前尚不具备的合成和计算概念。

换句话说,foo distinct 的原始操作;您不能根据合成本身来实现它。

答案 1 :(得分:1)

如果您真的要对此类高阶函数使用运算符,则可以为其修饰符。

$("#buttonR").click(function(){
    $(".changable").css({backgroundImage: "url("+ images[i % n].image +")" });
    $("#changeText").text(images[i % n].name);
    i++;
});