7

Browsing some internet board I encountered this little challenge:

"Implement a recursive anonymous function in your favorite language"

Obviously this is easy using a std::function/function pointer.

What I'm really interested in is if this is possible without binding the lambda to an identifier?

Something like (ignoring the obvious infinite recursion):

[](){ this(); }();
Xeo
  • 123,374
  • 44
  • 277
  • 381
user1233963
  • 1,390
  • 13
  • 36
  • 1
    Use the [fixed point combinator](http://stackoverflow.com/questions/152084/fixed-point-combinators-in-c) and you can turn any function into a recursive one. – didierc Mar 11 '13 at 17:58
  • 1
    Did you want no identifier, or did you really mean anonymous? C++ can have non-anonymous names that are _composed of_ identifiers but are themselves not identifiers. – Mooing Duck Mar 11 '13 at 18:20
  • By no identifier I mean no variable name – user1233963 Mar 11 '13 at 18:28

4 Answers4

5

Of course, in C++, to call any function you have to bind it to an identifier somewhere, simply owing to syntax constraints. But, if you will accept parameters as being sufficiently unnamed, then it is possible to create a version of the y-combinator in C++ which recurses nicely without being "named".

Now, this is really ugly because I don't know how to do a typedef for a recursive lambda. So it just uses a lot of cast abuse. But, it works, and prints FLY!! until it segfaults due to stack overflow.

#include <iostream>

typedef void(*f0)();
typedef void(*f)(f0);

int main() {
    [](f x) {
        x((f0)x);
    } ([](f0 x) {
        std::cout<<"FLY!!\n";
        ((f)x)(x);
    });
}

The two lambdas are unnamed in the sense that neither is explicitly assigned to name anywhere. The second lambda is the real workhorse, and it basically calls itself by using the first lambda to obtain a reference to itself in the form of the parameter.

Here's how you would use this to do some "useful" work:

#include <iostream>

typedef int param_t;
typedef int ret_t;

typedef void(*f0)();
typedef ret_t(*f)(f0, param_t);

int main() {
    /* Compute factorial recursively */
    std::cout << [](f x, param_t y) {
        return x((f0)x, y);
    } ([](f0 x, param_t y) {
        if(y == 0)
            return 1;
        return y*((f)x)(x, y-1);
    }, 10) << std::endl;
}
Community
  • 1
  • 1
nneonneo
  • 154,210
  • 32
  • 267
  • 343
3

Are you allowed to cheat?

void f(){
  []{ f(); }();
}

It's recursive - indirectly, atleast.

Otherwise, no, there is no way to refer to the lambda itself without assigning it a name.

Xeo
  • 123,374
  • 44
  • 277
  • 381
1

No identifier for functions/methods, Close enough or not !?

struct A
{
    void operator()()
    {
        [&]()
        {
            (*this)();
        }();
    }
};

To call

A{}(); // Thanks MooningDuck
masoud
  • 51,434
  • 14
  • 119
  • 190
  • 3
    That is basically the same as my answer, an indirection through a named function. Also, WTF `new A`. – Xeo Mar 11 '13 at 18:00
  • @MM. You can avoid the WTF by making the operator static, or (in C++11) `A{}()`. Also, the "name" of the function is `A::operator()`, so it's effectively the same as Xeo's. – Mooing Duck Mar 11 '13 at 18:06
  • The identifier is `operator()`. You could even call `a.operator()();`. Also, `A()()`. – Xeo Mar 11 '13 at 18:09
  • 1
    @Xeo: We can call it in the way you said, but an identifier should not has parentheses. So, it's just a way to call it. But `operator()` is not an identifier. – masoud Mar 11 '13 at 18:10
  • 1
    @MM. I just tested, it appears that operators can't be static. And you're right, a name is not an identifier. This has a name, but the function has no identifier. It only has an id. – Mooing Duck Mar 11 '13 at 18:16
  • `§13.5/1` "*operator-function-**id***" and `§1.6/2` "Names for syntactic categories have generally been chosen according to the following rules: — [...] — X-id is an **identifier** with no context-dependent meaning (e.g., qualified-id)." – Xeo Mar 11 '13 at 18:24
  • @Xeo: Well, It shows it's a _name_ not an _identifier_, however an _identifier_ is special case of a _name_. – masoud Mar 11 '13 at 18:49
  • No it does not show that, read again: "Names for syntactic categories". This refers to the "X-id" (or "operator-function-id") itself. – Xeo Mar 11 '13 at 18:57
0

I seem to have come up with a solution of my own:

#include <iostream>

int main()
{
    std::cout<<"Main\n";
    [&](){
        std::cout<<"Hello!\n";
        (&main+13)();
         }();
}

First call to cout is present just to show that it's not calling main.

I came up with the 13 offset by trial and error, if anyone could explain why it's this value it would be great.

user1233963
  • 1,390
  • 13
  • 36