chi*_*123 4 python functional-programming operators toolz
我正在慢慢尝试使用Python进行函数式编程,并遇到了以下问题:
给定两个函数f1和f2,我如何构造一个函数 f ,以“以函数方式”将这两个函数与相同的参数相乘?
没有深入研究函数式编程,我确实有一个解决方案
f = lambda x : f1(x) * f2(x)
Run Code Online (Sandbox Code Playgroud)
但它似乎不符合函数式编程的正确精神。
我的下一次尝试是使用像这样的mul和运算符juxt
>>> from tools import juxt
>>> from operator import mul
>>> f = mul(juxt(f1,f2))
TypeError: op_mul expected 2 arguments, got 1
Run Code Online (Sandbox Code Playgroud)
尝试拆分juxtwith的元组输出*也不起作用:
>>> f = mul(*juxt(f1, f2))
TypeError: mul() argument after * must be an iterable, not juxt
Run Code Online (Sandbox Code Playgroud)
再次使用lambda似乎有效,但不知何故它破坏了整个目的......
>>> temp = juxt(f_1, f_2)
>>> f = lambda x : mul(*temp(x))
Run Code Online (Sandbox Code Playgroud)
也许我在这里太迂腐或忘恩负义了(对Python),但我觉得我错过了函数式编程中一些非常重要或常规的东西。
有没有更实用的方法来做到这一点?
TL;DR 这种组合是一种原始操作(从某种意义上说,它不能分解为其他高阶函数),Python 和模块都不tools支持。您需要自己实施。
你缺少的(或者更确切地说,Python 和tools模块缺少的)是应用函子的概念。为了理解这意味着什么,我们首先回顾一下tools模块中的两个函数:
compose让您将两个函数链接在一起。那是,
compose(f,g) == lamba x: f(g(x))
Run Code Online (Sandbox Code Playgroud)curry与部分应用相关:演示比解释更快:
curry(f)(x)(y) == f(x, y)
Run Code Online (Sandbox Code Playgroud)
也就是说,curry(f)(x)与 基本相同partial(f, x);两者都接受一个值y来返回值f(x, y)。
此外,函子基本上是一种将函数映射到某个值的方法。您无疑熟悉列表函子:
map(f, [a,b,c]) == [f(a), f(b), f(c)]
Run Code Online (Sandbox Code Playgroud)
函数也是函子,但map我们使用来代替compose。也就是说,f映射g产生compose(f, g)。
现在,将mul, f1, 和f2组合成g = lambda x: g(f1(x), f2(x)),看起来两者compose和curry都会有用。以机智,
lambda x: mul(f1(x), f2(x)) == lambda x: curry(mul)(f1(x))(f2(x))
Run Code Online (Sandbox Code Playgroud)
和
lambda x: mul(f1(x), f2(x)) == lambda x: compose(curry(mul), f1)(x)(f2(x))
Run Code Online (Sandbox Code Playgroud)
(也就是说,curry这使得我们能够将两个参数的函数与另一个函数组合起来。)
但从某种意义上说,合成严格来说是一种线性运算。一个函数的输入来自另一个函数的输出。mul和 的组合f1创建一个需要参数的函数,并返回一个需要相同参数的函数。我们如何摆脱x这两个表达式的“中间”?我们需要的是一些神秘的函数,foo例如
foo(f, g) = lambda x: f(x, g(x))
Run Code Online (Sandbox Code Playgroud)
这使得函数将其参数传递给和 f,g同时还将结果传递g(x)给f。有了这样的函数foo,我们可以写
lambda x: foo(compose(curry(mul), f1), f2)
Run Code Online (Sandbox Code Playgroud)
并得到我们想要的结果。
这给我们带来了应用函子的想法。它提供了必要的功能foo
def foo(f, g):
def _(x):
return f(x, g(x))
Run Code Online (Sandbox Code Playgroud)
它结合了我们目前没有的组合和柯里化的概念。
换句话说,foo是一个独特的原始操作;你不能根据组合本身来实现它。