Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Vrije Universiteit, Faculty of Science and Bio-Engineering Sciences, Department of Computer Science, Brussels, Belgium
1
Austin /Functional Programming in C++14
programming language, this translates also to higher different approach. However, C++ (along with Lisp, and
productivity (Haskell.org, Functional programming, 2014). Python among others) is a multi-paradigm language. It
4.2 Modularity supports several different approaches to writing a
A more practical benefit of functional programming is program; you can write programs or libraries that are
that it forces you to break apart your problem into small largely procedural, object-oriented, or functional in all of
pieces. Programs are more modular as a result. It's easier these languages. In a large program, different sections
to specify and write a small function that does one thing might be written using different approaches; the GUI
than a large function that performs a complicated might be object-oriented while the processing logic is
transformation. Small functions are also easier to read and procedural or functional, for example.
to check for errors (Ltd). 4.6 The auto keyword
4.3 Ease of debugging and testing The auto keyword when used as data type for an
Testing and debugging a functional-style program is identifier means that the exact data type of the identifier
easier. will be deduced by the compiler from the type of the
Debugging is simplified because functions are expression used to generate the result (cppreference.com,
generally small and clearly specified. When a program auto specifier (since C++11), 2016).
doesn't work, each function is an interface point where auto x = 1; //data type of ex is int
you can check that the data are correct. You can look at the auto f() { return x; } // return type is int
intermediate inputs and outputs to quickly isolate the const auto& f() { return x; } // return type is const int&
function that's responsible for a bug. auto f() {} // returns void
Testing is easier because each function is a potential auto g() { return f(); } // returns void
subject for a unit test. Functions don't depend on system The auto keyword enables us to write generic
state that needs to be replicated before running a test; functions, for example the following code will compile.
instead you only have to synthesize the right input and auto identity (auto x) { return x; }
then check that the output matches expectations (Ltd). std::cout << identity(34) << std::endl;
4.4 Composability std::cout << identity(3.4) << std::endl;
As you work on a functional-style program, you'll write std::cout << identity("hello world") << std::endl;
a number of functions with varying inputs and outputs. std::cout << identity('Q') << std::endl;
Some of these functions will be unavoidably specialized to In the following sections we look at some functional
a particular application, but others will be useful in a wide programming features and for each, show how C++
variety of programs. For example, a function that takes a supports the feature.
directory path and returns all the XML files in the 4.7 First-class functions
directory, or a function that takes a filename and returns The terminology "first-class" is a computer science
its contents, can be applied to many different situations. describes programming language entities that have no
Over time you'll form a personal library of utilities. restriction on their use, thus first-class functions can
Often you'll assemble new programs by arranging existing appear anywhere in the program that other first-class
functions in a new configuration and writing a few entities like numbers can, including as arguments to other
functions specialized for the current task (Ltd). functions and as their return values i.e. they can be passed
4.5 Structured Programming around within program in much the same way as other
Functional programming is known to provide better variables (Haskell.org, Functional programming,
support for structured programming than imperative What_is_functional_programming).
programming. To make a program structured it is We will see this as we cover the other features.
necessary to develop abstractions and split it into 4.8 Lambda and Anonymous functions
components which interface each other with those In functional programming, a function definition can be
abstractions. Functional languages aid this by making it applied without having its identity known; i.e. a function
easy to create clean and simple abstractions. It is easy, for can be anonymous. In C++, you create an anonymous
instance, to abstract out a recurring piece of code by function using a lambda expression. The syntax for of a
creating a higher-order function which will make the lambda expression is
resulting code more declarative and comprehensible [capture-list](arguments)->return type {function body}
(Haskell.org, Functional programming, 2014). You can apply the function the expression returns
4. SOME FEATURES OF FUNCTIONAL LANGUAGES straight away. For example, the following statement would
A programming paradigm would simply be defined display 56 on the scree.
as the way a programming language supports [](int x)->void {std::cout << x << std::endl;} (56);
decomposition of a problem. Functional programming The lambda expression is evaluated at compile time.
decomposes a problem into a set of functions. Ideally, For an anonymous function to be used elsewhere (i.e.
functions only take inputs and produce outputs, and don't not where it is defined) the block that has created function
have any internal state that affects the output produced passes it to the block of code that needs to use it. This is
for a given input. the way anonymous function as most commonly used in
A number of concepts and paradigms are specific to functional programming. An example is shown in the
functional programming, and generally foreign to feature, closure section.
imperative programming (including object oriented 4.9 Closure
programming). In this section we briefly discuss some of Being first-class also means that it is possible to define
these concepts and then show how C++ implements them. and manipulate functions nested in code blocks. Such a
The designers of some computer languages have nested function can be passed to another block of code, for
chosen one approach to programming that's emphasized. the receiving block to execute when it deems fit. But, as
This often makes it difficult to write programs that use a well as being a code block amenable to being passed
2
Austin /Functional Programming in C++14
around for deferred execution, it also carries the context in 4.11 Higher-order functions (HOFs)
which it was defined, and thus can reference variables, etc. A higher-order function is a function which does at least
from that context. Such a function is said to close over the one of the following (Wikipedia, Map (higher-order
environment in which it was created and is known as a function)):
closure. So simply a closure is a function defined in a code takes one or more functions as an input
block, can be passed to another function and wherever it (arguments)
lands, it can still remember the code block it was created outputs (returns) a function.
in. The following is a higher order function. It takes three
The variable(s) from the context of the closure that it arguments one of which is a binary function and applies
can access while executing wherever it lands is are “bound the function (the third argument) to the two arguments.
in”in the closure function. The closure is “closed over a auto binaryAdder = [](auto arg1, auto arg2){ return arg1 +
free variable(s)” – hence the term closure. In other words, arg2; };
a closure is a function that makes use of free variables in auto aHoF = [](auto arg1, auto arg2, arg3) {
its definition. It 'closes' around some portion of its return arg3(arg1 + arg2);
environment (Haskell.org, Closure, 2010). The closure is };
constructed by returning it from another function which int x = aHoF(5, 3, binaryAdder); //applies binaryAdder to
creates the binding. 3 and 5
A simple example will illustrate this. The outer Function The value assigned to the variable x is 8, the sum of 5
in the code below is assigned a function that defines and and 3.
returns another function. The outerFunction is therefore 4.12 map, filter and fold
also the context of the nested function that is returned. Where a traditional imperative program might use a
The nested function can access the argument of the outer loop to traverse a list, a functional style would often use a
function. The call to outerFunction returns the inner higher-order function for example, map, a filter or a fold.
function with outerArg bound to the innerFunction. The map is the name of a higher-order function that applies
variable innerFunction is then a function that takes one a given function element-wise to a list of elements and
argument and returns the sum of 39 and that argument. returns a list of results. Typically,map takes a function and
auto outerFunction = [](auto outerArg) a list as its arguments, applies the function to each element
{return [=] (int innerArg)->auto{ return outerArg + of the list and returns the list as its result. The C++’s
innerArg; }; standard library contains lots of these functions. Some are
}; mutating algorithms (transform their list arguments) and
auto innerFunction = outerFunction(39); others non-mutating algorithms. The transform algorithm
std::cout << innerFunction(12) << std::endl; // output is applies the function argument it receives to a range/list of
51 values. Here is an example from (Wikipedia, Map (higher-
Note: In C++, closures do not extend the lifetime of order function))using a vector as the list.
their context. (If you need this, use you use shared_ptr) auto outerFunction = [](auto outerArg) {
(Tambe) return [=] (auto innerArg){ return outerArg + innerArg;
Note: In a function declaration which does not use the };
trailing return type syntax, the keyword auto indicates };
that the return type will be deduced from the operand of std::vector<int> vec(5,13); //5 int elements, all equal to 13
its return statement using the rules for template argument std::vector<int>::iterator it;
deduction. for (it = vec.begin(); it != vec.end(); it++)
Note: The term closure is often mistakenly used to std::cout << *it << " "; std::cout << std::endl;
mean anonymous function. This is probably because most vec[3] = 6;
languages implementing anonymous functions allow them auto innerFunction = outerFunction(9);
to form closures and programmers are usually introduced std::transform(vec.begin(),vec.end(),vec.begin(),innerFunc
to both concepts at the same time. These are, however, tion);
distinct concepts. A closure retains a reference to the for (it = vec.begin(); it != vec.end(); it++)
environment at the time it was created (for example, to std::cout << *it << " "; std::cout << std::endl;
the current value of a local variable in the enclosing scope) Higher-order functions are very useful for refactoring
while a generic anonymous function need not do this. [5] code and reduce the amount of repetition.
4.10 Partial Application The output of the above code is
Partial application (or partial function application) 13 13 13 13 13
refers to the process of fixing a number of arguments to a 22 22 22 15 22
function, producing another function of smaller arity The map is an in-place operation; it returns a
(Wikipedia, Partial application). modification of its input. A filter is like a map because its
The function call to outerFunction in the example output is a list, but unlike a map, a filter is noninvasive; it
given above is an example of partial application of a leaves its list input intact. Instead, it produces another list
function. The full application requires a call to the function whose members are only the members of the original list
it returns. An example of a full application is that pass a test. It filters out the elements in a list that
int x = outerFunction(12)(6); //value of x becomes 12 + 6 don’t pass a test. This function is pure. It does not modify
which is 18 the array it is given (Wikipedia, Filter (higher-order
If you call it with one argument, you get a special function)).
version of it that has the first argument bound, and The fold, also known variously as reduce, accumulate,
waiting for the second argument for full application; you compress or inject, is a family of higher-order functions
get a closure. that process a data structure in some order and build up
3
Austin /Functional Programming in C++14
4
Austin /Functional Programming in C++14
auto bindOperation = [] (auto monadicValue) { Most training institutions use C++ specially to teach
return [=] (auto transform){ OOP and sometimes procedural programming. I hope the
//line below feeds plain value into the transformation readersof this paper especially trainers and curriculum
function makers will see that C++ can adequately be used to teach
return transform(monadicValue()); the functional programming paradigm too and bring back
}; functional programming into their curricula if it is not
auto returnOperation = [] (auto plainValue){ there or lift it from obscurity if it is there.
return [=] (auto aBindOp){ REFERENCES
return [1] B. Stroustrup, "C++11 - the new ISO C++ standard,"
aBindOp(monadicValueConstructor(plainValue)); Columbia University, [Online]. Available:
}; http://www.stroustrup.com/C++11FAQ.html. [Accessed
}; 18 March 2016].
[2] C. Kohlhepp, "Chris Kohlhepp's Blog," [Online].
4.15 Recursion Available: https://chriskohlhepp.wordpress.com/lambda-
Recursive functions invoke themselves, allowing an over-lambda-in-cplusplus14/. [Accessed 18 March 2016].
operation to be performed over and over. Recursion is [3] cppreference.com, "auto specifier (since C++11),"
heavily used in functional programming as it is the cppreference.com, 25 January 2016. [Online]. Available:
canonical and often the only way to iterate (loop) http://en.cppreference.com/w/cpp/language/auto.
(Haskell.org, Functional programming, Recursion, 2016). [Accessed 18 March 2016].
Loops are naturally expressed using tail recursion. A [4] Wikipedia, "Monad (functional programming),"
tail recursion is characterised by the use of only one Wikipedia, 23 February 2016. [Online]. Available:
recursive call at the very end of a function https://en.wikipedia.org/wiki/Monad_%28functional_pro
implementation. In other words, when the call is made, gramming%29. [Accessed 19 March 2016].
there are no other statements left to be executed by the [5] Haskell.org, "Functional programming," Haskell.org, 24
function; the recursive call is not only the last statement, December 2014. [Online]. Available:
but there are no earlier recursive calls, direct or indirect. https://wiki.haskell.org/Functional_programming.
Is there any advantage in using tail recursion over [Accessed 18 March 2016].
iteration? In languages such as C++, there may be no [6] A. S. P. Ltd, "Fuctional programming Languages,"
compelling advantage, but in a language such as Prolog, Augment Systems Pvt. Ltd , [Online]. Available:
which has no explicit loop construct (loops are simulated http://www.assignmenthelp.net/pg/functional_program
by recursion), tail recursion acquires a much greater ming_languages. [Accessed 18 March 2016].
weight. In languages endowed with a loop or its [7] Haskell.org, "Functional programming,
equivalents such as an if statement combined with a go to What_is_functional_programming," Haskell.org, [Online].
statement, tail recursion should not be used (Drozdek, Available:
2005). https://wiki.haskell.org/Functional_programming#What_i
Recursion in C++ is straight forward. You simply write s_functional_programming.3F. [Accessed 18 March 2016].
code that make function call to the function whose body [8] Haskell.org, "Closure," Haskell.org, 29 September 2010.
the code appears in. The code below prints 1, 2, 3, 4, 5, 6, 7, [Online]. Available: https://wiki.haskell.org/Closure.
8, 9, using the for loop construct. [Accessed 18 March 2016].
for (int i =1; i < 10; i++) std::cout << i << “, “; [9] S. Tambe, "C++ Truths," [Online]. Available:
This can be achieved using recursion. The function http://cpptruths.blogspot.be/2014/03/fun-with-
below will produced the same output if called as lambdas-c14-style-part-1.html . [Accessed 18 March
printSerial(10). 2016].
void printSerial(int x) [10]
{ Wikipedia, "Partial application," Wikipedia, [Online].
if (x > 0) Available:
{ https://en.wikipedia.org/wiki/Partial_application.
printSerial(x - 1); [Accessed 18 March 2016].
std::cout << x << “, “; [11] Wikipedia, "Map (higher-order function)," Wikipedia,
} [Online]. Available:
else https://en.wikipedia.org/wiki/Map_%28higher-
return; order_function%29. [Accessed 19 March 2016].
} [12] Wikipedia, "Filter (higher-order function),"
5. CONCLUSION Wikipedia, [Online]. Available:
C++ is a really a big language. One should choose the https://en.wikipedia.org/wiki/Filter_%28higher-
most suitable features when writing a program. There are order_function%29. [Accessed 19 March 2016].
many choices to make depending on what kind of program [13] Haskell.org, "Fold," Haskell.org, 17 June 2015.
you are writing. The choice should be influenced by [Online]. Available: https://wiki.haskell.org/Fold.
whether you are building components or writing a [Accessed 19 March 2016].
program that uses component. [14] cppreference.com, "std::count, std::count_if,"
Into this mix of choices is also the programming style cppreference.com, [Online]. Available:
you use. As I have illustrated in this paper, functional http://en.cppreference.com/w/cpp/algorithm/count.
programming has its advantages and in a large program, [Accessed 19 March 2016].
different sections might be written using different [15] Wikipedia, "Lambda calculus," Wikipedia, [Online].
programming styles. Available:
5
Austin /Functional Programming in C++14
Appendix
The code below is the one that illustrates monads. It contains the essential components of a monad and the main function.
#include <iostream>
auto monadicValueConstructor = [] (auto plainValue) {
return [=] {
return plainValue;
};
};
auto transformFunction = [] (auto plainValue){
std::cout << plainValue << std::endl;
auto newValue = monadicValueConstructor(plainValue+3); //new monadic value
return [=] (auto aBindOp){
return aBindOp(newValue);
};
};
auto bindOperation = [] (auto monadicValue) {
return [=] (auto transform){
//line below feeds plain value into the transformation function
return transform(monadicValue());
};
auto returnOperation = [] (auto plainValue){
return [=] (auto aBindOp){
return aBindOp(monadicValueConstructor(plainValue));
};
};
int main(int argc, char **argv)
{
auto plainValue = 45; //plain value, a
returnOperation(plainValue)
(bindOperation)(transformFunction)
(bindOperation)(transformFunction)
(bindOperation)(transformFunction);
return 0;
}
Output
How to cite Article: WETOYI, Austin Owino. FUNCTIONAL PROGRAMMING IN C++14. Asian Journal of Computer
Science and Information Technology, [S.l.], v. 6, n. 1, p. 1-6, apr. 2016. ISSN 2249-5126. Available at:
<http://innovativejournal.in/ajcsit/index.php/ajcsit/article/view/39>. Date accessed: 10 Apr. 2016.
doi:10.15520/ajcsit.v6i1.39.