wake-up-neo.com

Anonym rekursiv PHP Funktionen

Ist es möglich, eine PHP - Funktion zu haben, die sowohl rekursiv als auch anonym ist? Dies ist mein Versuch, damit es funktioniert, aber der Funktionsname wird nicht übergeben.

$factorial = function( $n ) use ( $factorial ) {
    if( $n <= 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );

Mir ist auch bewusst, dass dies ein schlechter Weg ist, um factorial zu implementieren, es ist nur ein Beispiel.

177
Kendall Hopkins

Damit es funktioniert, müssen Sie $ factorial als Referenz übergeben

$factorial = function( $n ) use ( &$factorial ) {
    if( $n == 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
324
Derek H

Ich weiß, dass dies kein einfacher Ansatz ist, aber ich lernte eine Technik namens "fix" aus funktionalen Sprachen. Die fix-Funktion von Haskell ist allgemeiner als der Y-Combinator bekannt, der einer der bekanntesten Festkomma-Kombinatoren ist. 

Ein fester Punkt ist ein Wert, der von einer Funktion nicht geändert wird: Ein fester Punkt einer Funktion f ist ein beliebiges x mit x = f (x). Ein Festkomma-Kombinator y ist eine Funktion, die einen Festpunkt für jede Funktion f zurückgibt. Da y(f) ein fester Punkt von f ist, haben wir y (f) = f (y (f)).

Im Wesentlichen erstellt der Y-Combinator eine neue Funktion, die alle Argumente des Originals übernimmt, und zusätzlich ein Argument, das die rekursive Funktion ist. Wie dies funktioniert, wird anhand der Notendarstellung deutlicher. Schreiben Sie Argumente nicht in Klammern (f(x,y,...)), sondern schreiben Sie nach der Funktion: f x y .... Der Y-Kombinator ist definiert als Y f = f (Y f); oder mit einem einzigen Argument für die rekursierte Funktion Y f x = f (Y f) x.

Da PHP nicht automatisch curry funktioniert, ist es ein bisschen hackend, fix funktionieren zu lassen, aber ich denke, es ist interessant.

function fix( $func )
{
    return function() use ( $func )
    {
        $args = func_get_args();
        array_unshift( $args, fix($func) );
        return call_user_func_array( $func, $args );
    };
}

$factorial = function( $func, $n ) {
    if ( $n == 1 ) return 1;
    return $func( $n - 1 ) * $n;
};
$factorial = fix( $factorial );

print $factorial( 5 );

Beachten Sie, dass dies fast das gleiche ist wie bei den einfachen Verschlusslösungen, die andere veröffentlicht haben. Die Funktion fix erstellt jedoch den Abschluss für Sie. Festkomma-Kombinatoren sind etwas komplexer als die Verwendung eines Verschlusses, sie sind jedoch allgemeiner und haben andere Zwecke. Während die Schließmethode eher für PHP geeignet ist (was keine besonders funktionale Sprache ist), ist das ursprüngliche Problem eher eine Übung als für die Produktion, daher ist der Y Combinator ein praktikabler Ansatz.

24
Kendall Hopkins

Die C-Level-Erweiterung mpyw-junks/phpext-callee bietet keine anonyme Rekursion ohne Zuweisung von Variablen.

<?php

var_dump((function ($n) {
    return $n < 2 ? 1 : $n * callee()($n - 1);
})(5));

// 5! = 5 * 4 * 3 * 2 * 1 = int(120)
4
mpyw

In neueren Versionen von PHP können Sie Folgendes tun:

$x = function($depth = 0) {
    if($depth++)
        return;

    $this($depth);
    echo "hi\n";
};
$x = $x->bindTo($x);
$x();

Dies kann möglicherweise zu merkwürdigem Verhalten führen.

0
jgmjgm

Sie können Y Combinator in PHP 7.1+ wie folgt verwenden:

function Y
($le)
{return
    (function ($f) 
     {return
        $f($f);
     })(function ($f) use ($le) 
        {return
            $le(function ($x) use ($f) 
                {return
                    $f($f)($x);
                });
        });
}

$le =
function ($factorial)
{return
    function
    ($n) use ($factorial)
    {return
        $n < 2 ? $n
        : $n * $factorial($n - 1);
    };
};

$factorial = Y($le);

echo $factorial(1) . PHP_EOL; // 1
echo $factorial(2) . PHP_EOL; // 2
echo $factorial(5) . PHP_EOL; // 120

Spielen Sie damit: https://3v4l.org/7AUn2

Quellcodes von: https://github.com/whitephp/the-little-phper/blob/master/src/chapter_9.php

0
Lei Fan