1

Possible Duplicates:
javascript: recursive anonymous function?
Anonymous recursive PHP functions

I was wondering... Is it possible to do recursion with anonymous function?

Here is one example: I need to get six-chars long string which may contain only numbers and spaces. The only rules are that it cannot start or end with spaces. We check for that and if that occurs - just call recursion on the same, anonymous, function. Just how!?

function() {

    $chars   = range(0, 9);
    $chars[] = ' ';
    length   = 6;
    $count   = count($chars);

    $string = '';
    for ($i = 0; $i < $length; ++$i) {

        $string .= $chars[mt_rand(0, $count - 1)];

    }

    $string = trim($string);

    if (strlen($string) !== $length) { // There were spaces in front or end of the string. Shit!

        // Do recursion.

    }

    return $string;

}
Community
  • 1
  • 1
daGrevis
  • 19,600
  • 35
  • 95
  • 134

4 Answers4

14

Yes it is, but I wouldn't recommend it as it's a bit tricky ;)

First possibility:

<?php
$some_var1="1";
$some_var2="2";
function($param1, $param2) use ($some_var1, $some_var2)
{
    call_user_func(__FUNCTION__, $other_param1, $other_param2);
}
?>

Another one:

<?php 
$recursive = function () use (&$recursive){ 
    // The function is now available as $recursive 
} 
?> 

Examples taken from http://php.net/

  • Thanks for 2nd way. That is the best way, in my opinion. – daGrevis Aug 14 '11 at 08:37
  • 2
    +1 The second one is really elegant! I always thought you'd need to use that crazy-looking Y-Combinator to do Lambda-Recursion ;) – NikiC Aug 22 '11 at 18:37
2

The answer is complicated but not impossible. It took me several minutes to figure out. We first must define a utility function called $combinator().

The solution to your problem:

$combinator(
function($self) { function() use (&$self) {
    $chars   = range(0, 9);
    $chars[] = ' ';
    length   = 6;
    $count   = count($chars);

    $string = '';
    for ($i = 0; $i < $length; ++$i) {
        $string .= $chars[mt_rand(0, $count - 1)];
    }
    $string = trim($string);

    if (strlen($string) !== $length) {
        return $self();
    }
    return $string;
} }
);

The definition of $combinator():

$combinator = function($principle)
{
  (function($transept) use (&$principle)
  {
    $principle(
      function($arguments) use (&$transept)
      {
        call_user_func_array($transept($transept), $arguments));
      }
    );
  })
  (function($transept) use (&$principle)
  {
    $principle(
      function($arguments)
      {
        call_user_func_array($transept($transept), $arguments);
      }
    );
  });
}
1

A much saner method to do the same thing. Requires only one loop as well.

$chars = array_merge(range(0, 9), array(' '));

$string = mt_rand(0, 9);
for ($i = 1; $i <= 4; $i++) {
    $string .= $chars[array_rand($chars)];
}
$string .= mt_rand(0, 9);

Sorry for sidestepping the actual question though.

deceze
  • 471,072
  • 76
  • 664
  • 811
0

use goto

function() {
    start:
    $chars   = range(0, 9);
    $chars[] = ' ';
    length   = 6;
    $count   = count($chars);

    $string = '';
    for ($i = 0; $i < $length; ++$i) {

        $string .= $chars[mt_rand(0, $count - 1)];

    }

    $string = trim($string);

    if (strlen($string) !== $length) { // There were spaces in front or end of the string. Shit!

        goto start;

    }

    return $string;

But it's not the best idea to use goto.

the_drow
  • 17,134
  • 23
  • 116
  • 185
genesis
  • 48,512
  • 18
  • 91
  • 118
  • 3
    While this work, I would strongly advise to not use gotos if you can. Replacing your function with a real one with args and doing the recursion there is the best option. – Alexis Métaireau Aug 14 '11 at 08:31
  • @AlexisMétaireau: yes I think it's better idea but OP wanted to do it WITH ANONYMOUS function, so I see no reason for your downvote – genesis Aug 14 '11 at 08:32
  • downvoter: do you care to explain ? – genesis Aug 14 '11 at 08:33
  • Programmers see goto and are immideitly terrified. This is a good thing. I don't think you'd be downvoted if you also advised against it. – the_drow Aug 14 '11 at 08:35
  • @the_drow: added "But it'S not the best idea to use goto." – genesis Aug 14 '11 at 08:37
  • GOTO was defended by Knuth. It can't be all bad. – cwallenpoole Aug 14 '11 at 08:37
  • 1
    this answer basically says: i dont know how to do recursive anonymous functions, so i cheat with goto – Gordon Aug 14 '11 at 08:39
  • @Gordon: tell me, what's wrong with goto? – genesis Aug 14 '11 at 08:40
  • @genesis you are not building a compiler and its a kludge to do a *recursive anonymous function* with it. – Gordon Aug 14 '11 at 08:45
  • @Gordon: does it matter? goto is there (in PHP) to be used. – genesis Aug 14 '11 at 10:09
  • 2
    @genesis You can code your entire script with just `if` and `goto` and not use `for`, `while` or functions or classes. But scripts written that way are a step back into the 70s. We do not write code this way anymore because we have better tools for the job nowadays. See https://secure.wikimedia.org/wikipedia/en/wiki/GOTO#Criticism_and_decline or http://stackoverflow.com/questions/46586/goto-still-considered-harmful or http://stackoverflow.com/questions/4843551/what-are-the-valid-use-cases-of-goto-in-php – Gordon Aug 14 '11 at 10:31