This one is longer than the traditional exercises we post here and is meant to be a gentle introduction to the Functional Programming paradigm. But first some (uber simplified) theory:
Manipulating functions
Most of you are already familiar with the following concepts and can easily skip it and start programming. For the rest of you who are completely new to this, a small introduction.
If you come from an exclusive background in C, C++, C# or Java (and to a large extent PHP), this should help you understand the most recent evolutions of your language.
1- Higher order functions: functions vs data
You may have learned that your code consists of two things: The data you are manipulating (usually organized in some sort of data structure, like a dictionary or a list), and the functions you are applying on these structures.
One of the main features of functional programming is that functions are treated exactly like data, and can be manipulated and modified dynamically at run-time[*]. You will sometimes hear the term
higher-order functions. A HO function is a function that accepts another function as argument and/or returns another function. A dead simple example in python:
def say_hello():
print 'hello'
# The argument f is a function
def twice(f):
""" calls the function f two times. For example
>>> twice(say_hello)
hello
hello
"""
f()
f()
[*] - Note that Lisp, one of the first functional-flavored languages,
stretches this concept to the extreme.[/i]
2 - Iterables
When I say iterables, I mean any collection of data that can be iterated over. This could mean, for instance, an array, a linked list, a stack or the keys of a dictionary. One way to look at it is to consider iterable as a super class (or an interface) for all these data containers.
If you're familiar with iterators, then it's the preferred way to do this exercise. If not, you could work on any list of elements. For example:
- any of Vector, ArrayList or Linked Lists in C++, C# and Java.
- Linked Lists in C. To make it easier, consider a linked list of integers.
- Arrays in PHP, Perl and Ruby.
- Lists in Python.
- Tables in Lua.
- ...
Exercise
The goal of this exercise is to write a small library adding functional flavor to your favorite language.
Note that most familiar languages here on the forum, will implement them natively (C is the only one I can think of which doesn't); obviously the goal is to reimplement them, so do not use them in your solutions.
Higher Order functions
-
map(func, iter)
returns an iterable containing func(x) for each x in iter.
e. g: map(double, [1, 2, 3]) -> [2, 4, 6]
-
filter(func, iter)
returns an iterable containing each x in iter, such as func(x) == True
e. g: filter(is_even, [1, 2, 3, 4]) -> [2, 4]
-
head(iter)
returns the first element of the iterator
e. g: head([1, 2, 3]) -> 1
-
tail(iter)
returns the iterable minus its first element
e. g: tail([1, 2, 3]) -> [2, 3]
-
range(start, end)
returns an iterable containing all the integers from start to end-1
e. g: range(3, 8) -> [3, 4, 5, 6, 7]
Operators
This idea is taken from
Python.
Write a function that behaves like each of the following operators:
+, *, -, /, %
==, !=, >, >=, <, <=
or, and, not
Bonus points (intermediate)
Write the HO function
accumulate:
-
accumulate(func, iter, initial)
returns a single value obtained by successively calling func
on the elements of the iterator (and starting with the initial value).
e. g: accumulate(operator.add, [1, 2, 3], 10) -> 16
explanation:
- operator.add is the function that takes two args and returns their sum.
- 16 is therefore the sum of all the elements plus the initial value(10).
- 1 + 2 + 3 + 10 = 16
Question:
What happens if func is not associative? What is the result of accumulate(operator.divide, [1, 2, 3, 4, 5], 1)?
How can you solve that ambiguity?
Bonus points (difficult)
How can you make the function
range() lazily evaluated, without using yield or other builtin mechanisms?