You could do it like this, but it is almost unreadable. I hope the explanations are helpful:
def multiadder(n):
assert n > 0
if n == 0:
return 0
else:
return (lambda f: lambda i, n, sm: f(f, i, n, sm))(
lambda rec, i, n, sm: sm+i if n == 0 else lambda j: rec(rec, j, n-1, sm+i)
)(0, n, 0)
See it run on repl.it.
How it works
The return value consists of three major parts:
(lambda f: lambda i, n, sm: f(f, i, n, sm))
In short, this function assigns a name to a function, so it can be called recursively. In more detail:
It takes a function f
that must itself accept 4 arguments, of which the first should be a self-reference.
The function that is returned here takes the three other arguments, and returns the recursive call of f
.
Part two is the real core:
(lambda rec, i, n, sm: sm+i if n == 0 else lambda j: rec(rec, j, n-1, sm+i))
This is passed as argument to the first function above, making recursion possible.
This function takes the 4 arguments mentioned above, and applies the specific logic:
i
is the number that must be added
n
is the number of values still expected after this one
sm
is the so far accumulated sum (excluding i
)
Depending on whether more values are expected this function returns the final result (sm+i
) or
a function with one argument that will do the same as described here (recursion) with decreased n
, and adapted sum.
Finally, the initial values are passed to the above:
(0, n, 0)
Meaning, we start with number 0 (dummy), n
expected values, and a current sum of 0.
Note
As the recursion in the above code does not involve a call to multiladder
, and the assertion really excludes the if
condition to be true, we can do without that if...else
:
def multiadder(n):
assert n > 0
return (lambda f: lambda i, n, sm: f(f, i, n, sm))(
lambda rec, i, n, sm: sm+i if n == 0 else lambda j: rec(rec, j, n-1, sm+i)
)(0, n, 0)