views:

125

answers:

3

When I started writing this question, I didn't think of the easy solution with nested lists, but now anyway want to find one.

Here's an ugly code:

fun0(
    fun1(fun2(fun3(arg1))),
    fun1(fun2(fun3(arg4))),
    fun1(fun2(fun3(arg4))),
    fun1(fun2(fun3(arg4))))

Ouch! Names are given for examples. In the real application, their names have no pattern like this.

I played a bit with map(map ...) and reduce(map ...) getting wrong results or TypeErrors, before going here and writing this. The simple solution, of course, came while writing the question: use list comprehensions. Something like this (haven't tested yet):

fun0([i(j) for i in (fun1, fun2, fun3) for j in (arg1, arg2, arg3, arg4)])

Still, I'd like to know how is it possible to achieve the same with functional programming tools only?

fun0(map(fun1, map(fun2, map(fun3,
(arg1, arg2, arg3, arg4)))))

There's still a pattern that I think can be removed. I tried map(map, (fun1, ...), (arg1, ...)) but this way Python tried to iterate over each argument and raised errors.

+1  A: 

your 3 examples do 3 different things.

your original is the same as

fun0(map(lambda x:fun1(fun2(fun3(x))), [arg1,arg2,arg3,arg4])

your second example, if you absolutely want a functional form, is probably something like

fun0(map(apply, itertools.product([fun1,fun2,fun3],[arg1,arg2,arg3,arg4])))
Jimmy
A: 
def composed(x): return fun1(fun2(fun3(x)))

fun0(*map(composed, (arg1, arg2, arg3, arg4)))

You could use a lambda, of course, instead of naming intermediate function composed, but I find this way more readable.

Note that the * is crucial, otherwise you're calling fun0 with a single argument, a list, instead of calling it with four arguments!-)

Alex Martelli
A: 

The most functional way to rewrite your first code block would be to compose the three functions, map the composed function over the list of arguments, then apply fun0 to the list. Python doesn't really have a natural way to do function composition, so something like Jimmy's solution is where you'll end up.

Python style tends to discourage lambdas, though, so I'd probably write it as a list comprehension instead of a map:

fun0(*[fun1(fun2(fun3(x))) for x in [arg1, arg2, arg3, arg4]])

EDIT: Missed that fun0 needs separate arguments, not a list; adding * as per Alex Martelli's post.

camccann