PHP中的咖喱

Currying in PHP

提问人:Vivek 提问时间:5/10/2023 更新时间:5/11/2023 访问量:81

问:

这次我正在尝试在 PHP 中实现 currying(就像我们在 Javascript 中所做的那样)。以下是我的代码,它不起作用:

<?php

function test(callable $fn){
    $reflection = new ReflectionFunction($fn);
    $args = count($reflection->getParameters());
    
    $curried =  function(...$currArgs) use($args, $fn){
        if(count($currArgs) == $args){
            return $fn(...$currArgs);
        }else{
            return function(...$currArgs2) use($args, $fn, $currArgs){
                return $curried(array_merge($currArgs, $currArgs2));
            };
        }
    };
    
    return $curried;
}


$c = test(fn($x, $y, $z) => $x + $y + $z);


echo $c(10)(20,30);

问题:

正如你在这里看到的,它给了我未定义的变量。$curried

问题:

我们如何递归调用相同的 curried 函数,因为我认为这里没有办法实现这一点?

预期输出:

预期的输出应与回调中一样60fn($x, $y, $z) => $x + $y + $z

PHP 咖喱

评论

0赞 Ken Lee 5/10/2023
这回答了你的问题吗?是否可以在 PHP 中调用方法?.我建议你看看被接受的答案(以及那些有赞成票的答案),看看其中任何一个是否符合你的要求。
0赞 Vivek 5/10/2023
@KenLee好吧,我看了看这个骗子,但公认的答案似乎远非讨好。他只是返回了一个函数,并通过传递参数来调用它,这不是 currying 的主要目标。这个答案看起来很接近,但我假设匿名函数的词法范围内的局部变量一旦函数调用退出就会被销毁,这与 Javascript 不同,因为变量会保持活动状态,直到不再调用内部匿名函数并且垃圾收集器履行其职责。

答:

1赞 Vivek 5/11/2023 #1

好吧,这对我来说是一个非常有趣的问题。Currying 具有良好的合成糖以及其他一些优点(例如在日志记录中,我们可以在多个 DEBUG/INFO 日志语句方法调用中缓存日期时间,而无需为每个日志语句传递 datetime 参数)。


  • 首先,在新的匿名回调中以递归方式调用时不可访问。为此,我们需要通过引用在参数中传入此变量。$currieduse

  • 其次,在回调之外计算参数计数似乎没有任何优势。因此,我们将其放在回调中。

  • 第三,在 中,我没有将它们作为可变长度参数传递,这导致了参数计数计算中的问题。所以,修复是.$curried(array_merge($currArgs, $currArgs2))$curried(...array_merge($currArgs, $currArgs2))

最终工作代码:

<?php

function test(callable $fn){
    
    $curried =  function(...$currArgs) use(&$fn, &$curried){
        
        $reflection = new ReflectionFunction($fn);
        $args = count($reflection->getParameters());
        
        if(count($currArgs) == $args){
            return $fn(...$currArgs);
        }else{
            return function(...$currArgs2) use( $fn, $currArgs, &$curried){
                return $curried(...array_merge($currArgs, $currArgs2));
            };
        }
    };
    
    return $curried;
}

$c = test(fn($x, $y, $z) => $x + $y + $z);

echo $c(10)(20,30),"\n";
echo $c(10,20)(30),"\n";
echo $c(10,20,30),"\n";

在线演示