1

I am trying to implement currying in PHP this time(just like how we do in Javascript). Below is my code which is not working:

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

Issue:

It is giving me undefined variable $curried as you can see here.

Question:

How can we recursively call the same curried function as I see no way to achieve this here?

Expected output:

The expected output should be 60 as done in the callback fn($x, $y, $z) => $x + $y + $z

Vivek
  • 75
  • 6
  • Does this answer your question? [Is it possible to curry method calls in PHP?](https://stackoverflow.com/questions/1609985/is-it-possible-to-curry-method-calls-in-php) . I suggest you look at the accepted answer (and those with upvotes) to see whether any one of them fits your requirements. – Ken Lee May 10 '23 at 08:10
  • @KenLee Ok, I looked at the dupe but the accepted answer seems far from currying. He just returned a function and called it by passing the arguments which isn't the primary goal of currying. [`This answer`](https://stackoverflow.com/a/46650656/19963199) looks close but I assume the local variables in the lexical scope of the anonymous function are destroyed once the function call exits unlike in Javascript as the variable stays alive until there are no more calls to the inner anonymous function and the garbage collector does it's duty. – Vivek May 10 '23 at 08:19

1 Answers1

1

Ok, this has been a pretty interesting problem for me. Currying has a good syntatic sugar along with several other advantages(like in logging, we can cache the datetime across multiple DEBUG/INFO log statement method calls without having the need to pass datetime parameter for each log statement).


  • First, $curried is not accessible when called recursively inside the new anonymous callback. For this to work, we need to pass in this variable in use parameters by reference.

  • Second, we don't seem to have any advantage of calculating the parameter count outside the callback. So, we put this inside the callback.

  • Third, in $curried(array_merge($currArgs, $currArgs2)) , I wasn't passing them as variable length arguments which was causing the problem in parameter count computation. So, fix is $curried(...array_merge($currArgs, $currArgs2)).

Final Working code:

<?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";

Online Demo

Vivek
  • 75
  • 6