I'm after something a little more elegant than this.
What is the most elegant way to implement F such that:
F(a,b,c,d,e) -> lambda args: a(b(c(d(e(*args)))))
I'm after something a little more elegant than this.
What is the most elegant way to implement F such that:
F(a,b,c,d,e) -> lambda args: a(b(c(d(e(*args)))))
You probably want reduce: maybe something like:
reduce(lambda x, y: y(x), [a, b, c, d, e], initial_value) y(x) is not a function composition. I think it should be reduce(lambda f, g: lambda *args: f(g(*args)), [a, b, c, d, e]).reduce(lambda x, y: y(x), [e, d, c, b, a], initial_value). Furthermore, in this method, e must take exactly one argument.a = lambda n: n + 2 b = lambda n: n * 2 def F(*funcs): def G(*args): res = funcs[-1](*args) for f in funcs[-2::-1]: res = f(res) return res return G >>> F(a, b)(1) 4 Or better with reduce like @DanielRoseman
def F(*funcs): def G(*args): return reduce(lambda x, y: y(x), funcs[-2::-1], funcs[-1](*args)) return G >>> F(a, b)(1) 4 You could even do it in a single line but I feel like it's less elegant:
def F(*funcs): return lambda *args: reduce(lambda x, y: y(x), funcs[-2::-1], funcs[-1](*args)) a(b(1)) returns 4, not 6. I think your function is doing b(a(1)).b(1) = 2 and a(2) = 4 therefore F(a, b)(1) should be 4, not 6. Your function is not applying a(b(*args)) but a(b(b(*args)))[-2::-1] start indexThis works with multiple input values so you can have lambdas which all take N paramters, and return N values.
def F(*funcs): def _(*arg): if len(arg) == 1: arg = arg[0] for f in reversed(funcs): arg = f(arg) else: for f in reversed(funcs): arg = f(*arg) return arg return _ Test (multiple):
a = lambda n,m: (n + m,m) b = lambda n,m: (n*m,n) print(F(a,b)(1,2)) >>> (3, 1) Test (single):
a = lambda n: n + n b = lambda n: n ** 2 print(F(a,b)(1)) >>> 2