=========================================================================
Building abstractions with recursive functions and higher-order functions
=========================================================================
In programming, we control the intellectual complexity of our programs
by **building abstractions** that hide details when appropriate.
You already know of one such means to build abstractions in Python:
the ability to **define your own functions**.
This allows you to chunk compound operations as conceptual units, give them a name and manipulate them.
In this module, you will explore two other means to build abstractions with functions: **recursive functions** and **higher-order functions**.
Recursive functions
-------------------
**1. Watch the introduction video and read the following summary paragraph.**
.. raw:: html
**Summary.**
Recursive definitions allow us to describe many complex concepts in a simple and elegant way.
Likewise, *recursive functions* in Python allow us to define methods for solving problems in a simple and elegant way.
When doing so, we think in terms of *base cases*, for which there is an immediate solution,
and *recursive cases*, for which we can define the solution to our problem in terms of solutions to smaller versions of the same problem.
Once the solution has been defined in such a way, translating it into Python code is a snap.
This frees us from without having to worry about a whole series of questions that would arise if we were to solve the problem iteratively
(how to traverse sub-problems, how to keep track of intermediate results, what the iteration variable is, what the stop conditions are…).
In other words, we have abstracted the solution from the nitty-gritty details of control flow, memory, etc.
**2. Read section 16.1 to 16.6 of the interactive book thinkcspy at:** https://runestone.academy/runestone/books/published/thinkcspy/IntroRecursion/toctree.html
Sections 16.5. and 16.6 use the ``turtle`` graphics module which you may not be familiar with, but you should still be able to grasp the code easily.
You can skip them if you want, but visualization is a powerful way to learn about recursion.
**3. Do some of the following practice exercises.**
You can move to the next section whenever you feel ready to learn more, but make sure to do at least two exercises (like any other programming concepts/techniques, recursive functions cannot be understood without practice).
**Time to complete.** [\*]: short, [\*\*]: medium, [\*\*\*]: long.
**Exercise 1.** [\*] Write a recursive function to reverse a list. (Hint: to concatenate two lists, use the '+' operator).
.. A solution: TBD
**Exercise 2.** [\*] Write a recursive function to reverse a list.
.. A solution: TBD
**Exercise 3.** [\*\*] Write a script that displays the Koch snowflake (`see on wikipedia `__) using a recursive function.
You can use the ``turtle`` graphics module to draw on screen
(as shown in `section 16.5 of thinkcspy `__).
A solution: `link to code `__.
**Exercise 4.** [\*\*] Write a script that returns the pathnames of all the files ending in ``.txt`` contained inside a directory (at any depth of the hierarchy). You will need to use ``os.listdir()`` and ``os.path.isdir()``.
**Exercise 5.** [\*\*] Write a recursive function to generate all permutations of a list of values. (This could be useful, e.g., to do a permutation test for statistical analyses.)
**Exercise 6.** [\*\*\*] Write a recursive function to evaluate an arithmetic expression given in Polish notation (i.e. prefix notation, `see on wikipedia `__)
.. A solution: TBD
**Exercise 7.** [\*\*\*] Produce strings from the MIU formal grammar and investigate the MU puzzle. See :ref:`detailed explanations on the MU Puzzle `.
.. A solution: TBD
Side remark: in some cases, recursive functions can take a prohibitive amount of time and/or memory. This happens when the same computations are performed many times. This issue can be addressed using *memoization*. If you are curious, you can read the article `Memoization in Python `__
Higher-order functions
----------------------
**1. Watch the introduction video.**
.. raw:: html
**2. Read section 1.6 Higher-Order Functions of the online textbook at:**
https://wizardforcel.gitbooks.io/sicp-in-python/content/6.html
This textbook is an adaptation for Python of the textbook cited at the bottom of the page. (Author’s note: I haven’t checked out the rest of this adaptation. I recommend to read the original book if you want to learn more.)
**Stop and think:** In the section of the book you have read, the functions ``summation`` and ``iter_improve`` were implemented iteratively, using a ``while`` statement. Can you think of how to implement them recursively?
**3. Do some of the following practice exercises.**
**Time to complete.** [\*]: short, [\*\*]: medium, [\*\*\*]: long.
**Exercise 1.** [\*]
Write a ``product`` function to compute the product of the values of a function at points over a given range (the function should be an argument of ``product``).
Then, define a function to compute the factorial in terms of ``product``.
Finally, use ``product`` to compute an approximation to pi using the Wallis product formula (`see on wikipedia `__).
**Exercise 2.** [\*\*]
The ``summation`` function (from the textbook section you read)
and the ``product`` function (defined above)
can be defined as special cases of an even more general ``reduce`` function
which has two more arguments:
``binary_operator`` (which specifies what operation should be applied to reduce all the values to a single one)
and ``neutral_element`` (which specifies what base value should be used when the range is empty).
Write such a ``reduce`` function, and then define ``summation`` and ``product`` functions in terms of ``reduce``.
Make sure to test your functions.
**Exercise 3.** [\*\*]
Write a function that finds a fixed point of a function
(`see on wikipedia `__)
starting from an initial guess value, which could be defined as:
``find_fixed_point(f, initial_value, error_margin)``.
The returned value, ``x``, should be such that ``abs(f(x) - x) < error_margin``. Then, define a function to calculate the square root of a positive number, using the property that the square root of x is a fixed point
for the function y -> 1/2 (y + x/y).
Make sure to test your square root function.
**Exercise 4.** [\*\*]
Write a function to numerically compute any statistic of an arbitrary random variable.
The statistic and the random variable should both be functions which are given as argument.
(Hints. A statistic can be defined as a function of a collection of samples, e.g. sample mean, sample variance. A random variable can be defined as a function that, when it is called, generates one sample.)
Reference
----------
This module was inspired by:
Abelson, Harold, and Gerald Jay Sussman. *Structure and interpretation of computer programs*. The MIT Press, 1996.
It is an excellent computer science textbook. If you are curious, go check it out, it is freely available online `as pdf `__ and `as a web document `__.