CyberSpy

Rantings from a guy with way too much free time

Recursion Revisited

Recursion, from more than one point-of-view.

A common programming idiom in computer science is solving a problem by self-reference, also known as recursion. In this post, we look at two different implementations of the same problem.

Solve a recursive problem in two different programming language paradigms

Let’s look at the solution to a simple problem, compute $f(x)=e^{x}$.

We will illustrate two separate solutions - one in a procedural language (python), and the other in a functional language (elixir).

Let’s start off with the functional language. Were does recursion come into play?

We define the function $f(x)=e^x$ as the infinite sum, $\text{ }f(x) = \sum_{n=0}^\infty{\frac{x^n}{n!}}$

In our solution below, we define two separate recursive functions, exp/2 and fac/1. What’s interesting to note here is how each of these functions has two separate definitions. This is an aspect of programming in elixir that elegantly uses pattern-matching to return different results depending upon the input. Our two functions nicely dovetail into the base-case and recursive case of a recursive algorithm.

For example, looking at exp/2, the first function definition returns 1 for any value of x (as indicated by the _ preceding the variable) and returns 1. This is the mathematical equivalent of $x^0=1\text{ for any }x$.

The second definition of exp/2 is the recursive case. for any value of $n\gt0$. Moreover, we define exp(x, n) as $\frac{e^x}{n!}$ + exp(x, n-1).

Similarly for the definition of fac/1 we see two definitions; one for $n=0$ and another for all values of $n\gt0$.

  def exp(_x, 0) do
	1
  end

  def exp(x, n) when n > 0 do
	(:math.pow(x,n) / fac(n)) + exp(x, n-1)
  end

  def fac(0) do
	1
  end

  def fac(n) when n > 0 do
	n * fac(n-1)
  end

  ## read from stdin and return a list of integers
  def read(line \\ []) do
    case IO.read(:stdio, :line) do
      :eof ->
	{:eof, line}

      {:error, reason} -> IO.puts "Error: #{reason}"

      data ->
	item = String.to_float(String.trim(data))
	line = line ++ [item]

	read(line)
    end

  end

end

# read n
_ = IO.gets(:stdio, "")
|> String.trim("\n")
|> String.to_integer

# read a list of integers
{:eof, l} = Solution.read()


Enum.each(l, fn x -> IO.puts "#{Solution.exp(x, 9)}" end)

The same program written in python looks as follows:

import math
def fac(n):
    if n == 0:
        return 1
    else:
        return n * fac(n - 1)

def exp(x,n):

    if n == 0:
        return 1.0
    else:
        return float(math.pow(x,n))/float(fac(n)) + exp(x, n-1)

print(exp(1.0,100))

Our python program declares two functions fac(n) and exp(x,n). Both of these functions are defined recursively, but this time rather than two separate functions like we see with elixir, we have the base-case of our function captured in an if-then-else clause. The if-clause implements the base-case, and the else-clause is our recursive definition.

comments powered by Disqus