再帰的かつ匿名のPHP関数を持つことは可能ですか? これは動作させるための私の試みですが、関数名は渡されません。
$factorial = function( $n ) use ( $factorial ) {
if( $n <= 1 ) return 1;
return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
また、これが階乗を実装する悪い方法であることも認識しています。これは単なる例です。
再帰的かつ匿名のPHP関数を持つことは可能ですか? これは動作させるための私の試みですが、関数名は渡されません。
$factorial = function( $n ) use ( $factorial ) {
if( $n <= 1 ) return 1;
return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
また、これが階乗を実装する悪い方法であることも認識しています。これは単なる例です。
それが機能するためには、参照として $factorial を渡す必要があります
$factorial = function( $n ) use ( &$factorial ) {
if( $n == 1 ) return 1;
return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
これが単純なアプローチではないことは承知していますが、関数型言語から「修正」と呼ばれる手法について学びました。Haskellのfix
関数は、より一般的にY コンビネータとして知られています。これは、最もよく知られている固定小数点コンビネータの 1 つです。
不動点は、関数によって変更されない値です。関数fの不動点は、x = f(x)となる任意のxです。不動点コンビネータyは、任意の関数 f に対して不動点を返す関数です。y(f) は f の不動点なので、y(f) = f(y(f)) となります。
基本的に、Y コンビネータは、元のすべての引数に加えて、再帰関数である追加の引数を取る新しい関数を作成します。これがどのように機能するかは、カリー表記を使用するとより明白になります。引数は括弧 ( f(x,y,...)
) ではなく、関数の後に記述しますf x y ...
。Y コンビネータは次のように定義されY f = f (Y f)
ます。または、再帰関数の単一の引数を使用して、Y f x = f (Y f) x
.
PHP は自動的に関数をカリー化しないので、機能させるには少しハックですが、fix
興味深いと思います。
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 );
これは、他の人が投稿した単純なクロージャー ソリューションとほぼ同じですが、関数fix
がクロージャーを作成することに注意してください。固定小数点コンビネータは、クロージャを使用するよりも少し複雑ですが、より一般的であり、他の用途があります。クロージャ メソッドは PHP (あまり機能的な言語ではない) に適していますが、元の問題は運用環境よりも演習に近いため、Y コンビネータは実行可能なアプローチです。
変数を定義せずに匿名クラス (PHP 7 以降) を使用する場合:
echo (new class {
function __invoke($n) {
return $n < 2 ? 1 : $n * $this($n - 1);
}
})(5);