Summation and product functions using functional paradigm Below is the problem:


  Show that both summation and product are instances of a more general function, called accumulate, with the following signature:

def accumulate(combiner, start, n, term):
    """Return the result of combining the first n terms in a sequence."""
    "*** YOUR CODE HERE ***"

  
  Accumulate takes as arguments the same arguments term and n as summation and product, together with a combiner function (of two arguments) that specifies how the current term is to be combined with the accumulation of the preceding terms and a start value that specifies what base value to use to start the accumulation. Implement accumulate and show how summation and product can both be defined as simple calls to accumulate:

def summation_using_accumulate(n, term):
    """An implementation of summation using accumulate.

    &gt;&gt;&gt; summation_using_accumulate(4, square)
    30
    """
    "*** YOUR CODE HERE ***"

def product_using_accumulate(n, term):
    """An implementation of product using accumulate.

    &gt;&gt;&gt; product_using_accumulate(4, square)
    576
    """
    "*** YOUR CODE HERE ***"



For which, solution is mentioned below:

from operator import add
from operator import mul

def square(x):
    """ Retrun x squared"""
    return x * x


def accumulate(combiner, start, n, term):
    """Return the result of combining the first n terms in a sequence."""
    if n == 0:
        return start
    else:
        start = combiner(term(n), start)
        return accumulate(combiner, start, n-1, term)

def summation_using_accumulate(n, term):
    """An implementation of summation using accumulate.

    &gt;&gt;&gt; summation_using_accumulate(4, square)
    30
    """
    assert n &gt;= 0
    return accumulate(add, 0, n, term)



def product_using_accumulate(n, term):
    """An implementation of product using accumulate.

    &gt;&gt;&gt; product_using_accumulate(4, square)
    576
    """
    assert n &gt; 0
    return  accumulate(mul, 1, n, term)    

result =  summation_using_accumulate(4, square)
print(result)
result = product_using_accumulate(3, square)
print(result)


Please let me know if this program can be improved further using functional paradigm and the DRY principle.
The start parameter of accumulate is a bit misleading.
My first thought was that start is the first element of the sequence,
but it's an accumulated value.
A more common name is acc or accum.

Reassigning function parameter is considered a bad practice, 
in any language as far as I remember.
It's basically reusing an input variable for one additional purpose.
start is an input to your function,
but when you reassign it, it becomes something else:
instead of being just the input,
now it carries the result of a calculation.
When you look at your function body,
the variable start is sometimes the input, 
sometimes the result of a local calculation.
This duality in purpose can be confusing and can lead to errors.
It's cleaner to assign the mutated value to a completely new local variable.

In this version, acc always has the same value,
there can be no confusion and misuse, it's perfectly clear:

def accumulate(combiner, acc, n, term):
    """Return the result of combining the first n terms in a sequence."""
    if n == 0:
        return acc
    else:
        next_acc = combiner(term(n), acc)
        return accumulate(combiner, next_acc, n-1, term)


The benefit may not be obvious in this simple function,
but I hope you see the truth in the principle of not reusing parameter variables.
In a longer, more complicated function the benefits would become more clear.

In languages that have out-parameters,
re-assignment of parameters forces me to double-check the signature.
Although Python doesn't have out-parameters,
I still review code like this with suspicion,
in case the author may have mistakenly believed that the re-assigned value will produce a side effect outside the function.
This may sound a bit paranoid, but I've seen this kind of thing happen more than once.
By not re-assigning parameters,
all suspicions are cleared, and the code is easier to review.

For the record, I was tempted to suggest to drop the else clause there,
to simplify to:

def accumulate(combiner, acc, n, term):
    """Return the result of combining the first n terms in a sequence."""
    if n == 0:
        return acc
    next_acc = combiner(term(n), acc)
    return accumulate(combiner, next_acc, n-1, term)


But then, most functional languages return the last evaluation,
and explicit return statements are not recommended,
which makes if-else necessary.
For example the Scala solution would look something like this:

def accumulate(combiner, acc, n, term): Int = {
    if (n == 0) {
        acc
    } else {
        val nextAcc = combiner(term(n), acc)
        accumulate(combiner, nextAcc, n-1, term)
    }
}


So using the explicit else clause is closer to the spirit of functional programming, so I'd leave that as you did.