web developer & system programmer

coder . cl

ramblings and thoughts on programming...


some C++0x functional programming features

published: 02-09-2009 / updated: 02-09-2009
posted in: c++, programming, tips
by Daniel Molina Wegener

I know a little about functional programming. Certainly, It have interesting features, such as Lambda Expressions and Closures. It seems that C++0x, the new C++ standard will support both of them. Closures, known as nested functions and Lambda Expressions, known as anonymous functions are neat tools on developing fast code with small pieces of them. Lambda expressions can be used as arguments. They allow certain kind of abstractions, allowing the implementation of computational structures like Monads and Monoids.

Lambda expressions are seen in functional languages like Lisp. Also multiparadigm languages, like Python and Ruby. We can review both of them from its origins, such as Lisp implementations.

Closures

From the Wikipedia article on closures:

In computer science, a closure is a first-class function with free variables that are bound by the lexical environment. Such a function is said to be “closed over” its free variables. A closure is defined within the scope of its free variables, and the extent of those variables is at least as long as the lifetime of the closure itself. The explicit use of closures are associated with functional programming and with languages such as ML and Lisp. Closures are used to implement continuation passing style, and in this manner, hide state. Constructs such as objects and control structures can thus be implemented with closures.

A closure is bound to nested functions. The scope of a nested function allows the reuse of variables which are local to the container function. In this case, a closure has the next form — if we review from the Lisp perspective:

;;; we have this file as test.l
(defun test-container (x)
  (defun test-closure (y)
    (format t "~10A" y))
  (test-closure x))

(test-container "hola")

From the Lisp interpreter:

>(load "test.l")

Loading test.l
hola
Finished loading test.l
T

If you look at the code, you have the test-closure nested function, or as it’s called closure. The C++0x standard allows the use of closures in the code, you can define nested functions.

### sample Python closure...
def test_container(x):
    def test_closure(y):
        print y
    test_closure(x)

test_container("hola")

The C++0x standard and the current working draft do not allow the direct declaration of nested functions or closures, but as is read in the current working draft: “The type of the closure object is a class with a unique name, call it F, considered to be defined at the point where the lambda expression occurs” [C++0x Working Draft, Sec. 5.1.2, P7]. Under this definition, and by using lambda expressions, we can define closures as follows:

#include <iostream>
#include <string>

class TestClass {
public:
    TestClass();
    int csum(int a, int b);
};

int
TestClass::csum(int a, int b) {
    // do you know what clos is? xD
    auto clos = [](int x, int y) -> int { int z = x * y; return y + z; };
    return clos(a, b);
}

int
main (int argc, char **argv) {
    TestClass *p = new TestClass();
    std::cout << p->csum(10, 13) << std::endl;
    return 0;
}

We have the magic keyword auto to define the anonymous class or anonymous closure object, then we can use the closure in our code. The closure itself is a Lambda Expression. So, let’s review what is a Lambda Expression.

Lambda Expressions

Lisp supports Lambda Expressions from its origins. A common example is the list and sequence processing statements where lambda expressions pass each element on sequences and lists to the anonymous functions. Let’s see an example.

The Wikipedia example on Lisp Lambda Expressions only shows an anonymous function:

(lambda (x) (* x x))

If I run GCL or SBCL, I can do a little bit more applied example:

>(defvar test '("piwidi" "yopuz" "gon"))
TEST
>(defvar test2 (map 'list #'(lambda (x) (concatenate 'string x " cheat chat")) test))
TEST2
>test2
("piwidi cheat chat" "yopuz cheat chat" "gon cheat chat")

The example above uses an anonymous function to concatenate each string on the test list with the suffix string ” cheat chat”, and uses the map call output to create the test2 variable. With a behavior pretty similar to what a monad does, since we can use anonymous functions as variables, in example as list members:

>(defvar test3 #'(lambda (x) (concatenate 'string x " cheat chat")))
TEST3
>test3
(LAMBDA-CLOSURE () () () (X) (CONCATENATE 'STRING X " cheat chat"))
;;; And then to use test3 as part of a list:
>(defvar test3 #'(lambda (x) (concatenate 'string x " cheat chat")))
TEST3
>(defvar test4 '(("gon" test3) ("yopuz" test3) ("piwidi" test3)))
TEST4
>test3
(LAMBDA-CLOSURE () () () (X) (CONCATENATE 'STRING X " cheat chat"))
>test4
(("gon" TEST3) ("yopuz" TEST3) ("piwidi" TEST3))

Other languages are also implementing lambda expressions. Python have the lambda keyword to allow the declaration of anonymous functions and there are interesting articles on Functional Programming under Python. And surely you can be impressed by viewing that many languages allow the use of code as argument, directly as functional paradigm does or indirectly as the imperative paradigm does by using callbacks.

The C++0x will allow the use of Lambda Expressions. If we look at the Wikipedia examples, the next statement:

[](int x, int y) -> int { int z = x + y; return z + y; }

Is a lambda expression. The first part [](int x, int y) -> int { have a semantic equivalence with #’(lambda (x, y), where x and y are both arguments to the anonymous function. Since Lisp is not strict with data typing, the C++0x expression allows to define the return type of the anonymous function with the statement -> int. The anonymous function body is { int z = x + y; return z + y; }, that is semantically equivalent to the let or progn body of the Lisp expression.

We considered the possibility of supporting polymorphic lambda functions, whose parameter types need not be specified. Such a lambda function would implicitly be an unconstrained template, accepting any argument types; the body would be checked against the particular argument types used when the call to the lambda function is instantiated. Such functions would not create significant difficulties for the proposed translation model. A lambda expression whose parameter types were not specified would simply be translated to a function object whose function call operator is a template. Such lambda functions would, however, clash with the modular type-checking which we attempt to introduce to C++ via concepts [SD05, GSW+ 05].
“Lambda expressions and closures for C++”

This is an interesting paragraph. Since anonymous functions are not templates, they will allow polymorphism with anonymous typing of their arguments, whereas those arguments will have typing constraints in the function implementation body and checked in run-time and driven by the use of standard C++ templates: A lambda expression whose parameter types were not specified would simply be translated to a function object whose function call operator is a template. Well, this paper is a quiet old, since C++0x Concepts were recently removed from the standard by the C++0x working committee. The proposal does not refers to implementation issues, but leads to implementation strategies, like the expensive compile time performance which requires those lambda expressions and closures, since the leading strategy sets both of them become as a new local class, meaning that those classes must be instantiated to allow the use of their behavior.

Now, why are closure objects important to the C++0x Lambda Expressions:

The evaluation of a lambda-expression results in a closure object, which is an rvalue. Invoking the closure object executes the statements specified in the lambda-expression’s compound-statement. Each lambda expression has a unique type. Except as specified below, the type of the closure object is unspecified. [Note: A closure object behaves as a function object (20.7) whose function call operator, constructors, and data members are defined by the lambda-expression and its context. — end note]

Then, closure objects are the core type of lambda expressions, since C++0x supports function objects, and C++0x comes with the <functional> header, to allow you to work with function objects and their declaring types and core operators:

Function objects are objects with an operator() defined. In the places where one would expect to pass a pointer to a function to an algorithmic template (clause 25), the interface is specified to accept an object with an operator() defined. This not only makes algorithmic templates work with pointers to functions, but also enables them to work with arbitrary function objects.

The interesting declaration on the <functional> header for closures is the function class: template<FunctionType> class function;, which keeps the class undefined to allow your custom definition and type hierarchy.

Take a look on the current working draft of the C++0x, it comes interesting ;)


No coments yet.

post a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>