Lambda-Over-Lambda in C++14

How following recursive lambda call ends/terminates ?

#include <cstdio>

auto terminal = [](auto term)            // <---------+  
{                                        //           |
    return [=] (auto func)               //           |  ???
    {                                    //           |
        return terminal(func(term));     // >---------+
    };
};


auto main() -> int
{
    auto hello =[](auto s){ fprintf(s,"Hello\n"); return s; };
    auto world =[](auto s){ fprintf(s,"World\n"); return s; };


    terminal(stdout)
            (hello)
            (world) ;

    return 0;

}

What am I missing over here ?

Running code


It's not a recursive function call, look at it step-by-step:

  1. terminal(stdout) - this simply returns a lambda which has captured stdout
  2. The result of 1. is called with the lambda hello, which executes the lambda (func(term)), the result of which is passed to terminal(), which simply returns a lambda as in 1.
  3. The result of 2. is called with the lambda world, which does the same as 2, this time the return value is discarded...

The call itself is not recursive. It returns a function object which, if called, will call terminal again to generate yet another function object.

So terminal(stdout) returns a functor which captures stdout and can be called with another function object. Calling it again, (hello), calls the hello functor with the captured term stdout, outputting "Hello"; the calls terminal and returns another functor which this time captures the return value of hello - which is still stdout. Calling that functor, (world), just the same again, outputting "World".


The key here is to understand that this is valid:

world(hello(stdout));

and will print "Hello World". The recursive series of lambdas can be unrolled as

#include <cstdio>

auto terminal = [](auto term)            // <---------+  
{                                        //           |
    return [=] (auto func)               //           |  ???
    {                                    //           |
        return terminal(func(term));     // >---------+
    };
};

/*
terminal(stdout) -returns> anonymous_lambda which captures stdout (functor)
anonymous_lambda(hello) is called, func(term) is hello(stdout) and prints "Hello" and returns stdout, the anonymous_lambda -returns> terminal(stdout)
(the above 2 lines start again)
terminal(stdout) is called and -returns> anonymous_lambda which captures stdout (functor)
anonymous_lambda(world) is called, func(term) is world(stdout) and prints "World" and returns stdout, the anonymous_lambda -returns> terminal(stdout)
terminal(stdout) is called and -returns> anonymous_lambda which captures stdout (functor)
nobody uses that anonymous_lambda.. end.
*/

auto main() -> int
{
    auto hello =[](auto s){ fprintf(s,"Hello\n"); return s; };
    auto world =[](auto s){ fprintf(s,"World\n"); return s; };

    world(hello(stdout));


    terminal(stdout)
            (hello)
            (world) ;

    return 0;

}

Coliru example