匿名递归 PHP 函数

发布于 2024-08-25 15:24:15 字数 256 浏览 8 评论 0原文

是否可以有一个既递归又匿名的 PHP 函数?这是我尝试让它工作,但它没有传递函数名称。

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

我也知道这是实现阶乘的一种不好的方法,这只是一个例子。

Is it possible to have a PHP function that is both recursive and anonymous? This is my attempt to get it to work, but it doesn't pass in the function name.

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

I'm also aware that this is a bad way to implement factorial, it's just an example.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

江挽川 2024-09-01 15:24:15

为了使其工作,您需要传递 $factorial 作为参考

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

In order for it to work, you need to pass $factorial as a reference

$factorial = function( $n ) use ( &$factorial ) {
    if( $n == 1 ) return 1;
    return $factorial( $n - 1 ) * $n;
};
print $factorial( 5 );
夜光 2024-09-01 15:24:15

我知道这可能不是一个简单的方法,但我了解了一种名为 "fix" 来自函数式语言。 Haskell 的 fix 函数通常被称为 Y 组合器< /a>,这是最著名的定点组合器之一。

不动点是一个不被函数改变的值:函数f的不动点是任何x,使得x = f(x)。定点组合器y是一个为任何函数f返回一个定点的函数。由于 y(f) 是 f 的不动点,因此有 y(f)=f(y(f))。

本质上,Y 组合器创建一个新函数,它接受原始函数的所有参数,再加上一个附加参数,即递归函数。使用柯里化表示法,其工作原理更加明显。不要将参数写在括号中 (f(x,y,...)),而是将它们写在函数后面:fxy ...。 Y组合器定义为Y f = f (Y f);或者,递归函数只有一个参数,Y fx = f (Y f) x

由于 PHP 不会自动使用 curry 函数,因此修复 有点麻烦 工作,但我认为这很有趣。

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 组合器是一种可行的方法。

I know this might not be a simple approach, but I learned about a technique called "fix" from functional languages. The fix function from Haskell is known more generally as the Y combinator, which is one of the most well-known fixed point combinators.

A fixed point is a value that is unchanged by a function: a fixed point of a function f is any x such that x = f(x). A fixed point combinator y is a function that returns a fixed point for any function f. Since y(f) is a fixed point of f, we have y(f) = f(y(f)).

Essentially, the Y combinator creates a new function that takes all the arguments of the original, plus an additional argument that's the recursive function. How this works is more obvious using curried notation. Instead of writing arguments in parentheses (f(x,y,...)), write them after the function: f x y .... The Y combinator is defined as Y f = f (Y f); or, with a single argument for the recursed function, Y f x = f (Y f) x.

Since PHP doesn't automatically curry functions, it's a bit of a hack to make fix work, but I think it's interesting.

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 );

Note this is almost the same as the simple closure solutions others have posted, but the function fix creates the closure for you. Fixed point combinators are slightly more complex than using a closure, but are more general, and have other uses. While the closure method is more suitable for PHP (which isn't a terribly functional language), the original problem is more of an exercise than for production, so the Y combinator is a viable approach.

临走之时 2024-09-01 15:24:15

虽然不用于实际使用,但 C 级扩展 mpyw-junks/phpext-callee 提供匿名递归无需分配变量

<?php

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

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

Although it is not for practial usage, The C-level extension mpyw-junks/phpext-callee provides anonymous recursion without assigning variables.

<?php

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

// 5! = 5 * 4 * 3 * 2 * 1 = int(120)
江挽川 2024-09-01 15:24:15

使用匿名类(PHP 7+),不定义变量:

echo (new class {
    function __invoke($n) {
        return $n < 2 ? 1 : $n * $this($n - 1);
    }
})(5);

With an anonymous class (PHP 7+), without defining a variable:

echo (new class {
    function __invoke($n) {
        return $n < 2 ? 1 : $n * $this($n - 1);
    }
})(5);
与之呼应 2024-09-01 15:24:15

在较新版本的 PHP 中,您可以这样做:

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

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

这可能会导致奇怪的行为。

In newer versions of PHP you can do this:

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

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

This can potentially lead to strange behaviour.

可是我不能没有你 2024-09-01 15:24:15

您可以在 PHP 7.1+ 中使用 Y Combinator,如下所示:

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

尝试一下:https://3v4l.org/7AUn2

源代码来自: https://github.com /whitephp/the-little-phper/blob/master/src/chapter_9.php

You can use Y Combinator in PHP 7.1+ as below:

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

Play with it: https://3v4l.org/7AUn2

Source codes from: https://github.com/whitephp/the-little-phper/blob/master/src/chapter_9.php

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文