Generatory rekurencyjne w PHP

Wprowadzenie

Od wersji 5.5 w PHP jest tak wspanialegeneratory. Nie powtórzę oficjalnej strony podręcznika, ale świetnie nadają się do krótkiej definicji iteratorów. Najbardziej znaną próbką jest:

function xrange($from, $till, $step)
{
   if ($from>$till || $step<=0)
   {
      throw new InvalidArgumentException('Invalid range initializers');
   }

   for ($i = $from; $i < $till; $i += $step)
   {
      yield $i;
   }
}

//...

foreach (xrange(2, 13, 3) as $i)
{
   echo($i.PHP_EOL); // 2,5,8,11
}

a generator w rzeczywistości nie jest funkcją, ale instancją konkretnej klasy:

get_class(xrange(1, 10, 1)); // Generator


Problem

Zrobione z rzeczy RTM, teraz przechodzę do mojego pytania. Wyobraź sobie, że chcemy stworzyć generatorLiczby Fibonacciego. Zwykle, aby je uzyskać, możemy użyć prostej funkcji:

function fibonacci($n)
{
   if(!is_int($n) || $n<0)
   {
      throw new InvalidArgumentException('Invalid sequence limit');
   }
   return $n < 2 ? $n : fibonacci($n-1) + fibonacci($n-2);
}

var_dump(fibonacci(6)); // 8

Przekształćmy to w coś, co trzymasekwencja a nie tylko jego ostatni członek:

function fibonacci($n)
{
   if (!is_int($n) || $n<0)
   {
      throw new InvalidArgumentException('Invalid sequence limit');
   }
   if ($n<2)
   {
      return range(0, $n);
   }
   $n1 = fibonacci($n-1);
   $n2 = fibonacci($n-2);
   return array_merge($n1, [array_pop($n1)+array_pop($n2)]);
}

//...

foreach (fibonacci(6) as $i)
{
   echo($i.PHP_EOL); // 0,1,1,2,3,5,8
}

Mamy teraz funkcję, która zwraca tablicę z pełną sekwencją


Pytanie

Wreszcie część pytania: jak mogę przekształcić moje najnowszefibonacci funkcja tak będziewydajność moje wartości, nie trzymając ich w tablicy? Mój$n może być duży, więc chcę korzystać z zalet generatorów, jak wxrange próba. Pseudo-kod będzie:

function fibonacci($n)
{
   if (!is_int($n) || $n<0)
   {
      throw new InvalidArgumentException('Invalid sequence limit');
   }

   if ($n<2)
   {
      yield $n;
   }

   yield fibonacci($n-2) + fibonacci($n-1);
}

Ale to oczywiście jest bzdura, ponieważ nie możemy sobie z tym poradzić w ten sposób, ponieważ rekursja spowoduje obiekt klasyGenerator i nieint wartość.

Premia: uzyskanie sekwencji fibonacci to tylko próbka dla bardziej ogólnego pytania: jak używać generatorów z rekursją w typowym przypadku? Oczywiście mogę używać standarduIterator w tym celu lub przepisz moją funkcję, aby uniknąć rekursji. Ale chcę to osiągnąć za pomocą generatorów. czy to możliwe? Czy to jest warte wysiłku, aby wykorzystać ten sposób?

questionAnswers(8)

yourAnswerToTheQuestion