2010-03-19 7 views
150

재귀 적이며 익명 인 PHP 함수를 사용할 수 있습니까? 이것은 작동시키려는 시도이지만 기능 이름은 전달하지 않습니다.익명 재귀 PHP 함수

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

나는 이것이 계승을 구현하는 나쁜 방법임을 알고 있으며, 이는 단지 예일뿐입니다. 그것이 작동하기 위해서는

+0

확인하려면 PHP 5.3.0이 없지만'global $ factorial'을 사용해 보셨습니까? – kennytm

+4

* (sidenote) * Lamba는 익명 함수이고 위의 값은 Closure입니다. – Gordon

+1

람다와 클로저는 상호 배타적이지 않습니다. 사실 어떤 사람들은 closure가 closure (익명의 함수)가되기 위해서는 닫는 것이 람다 (lambda) 여야한다고 믿습니다. 예를 들어 파이썬의 경우에는 함수의 이름을 먼저 지정해야합니다 (버전에 따라 다름).당신이 그것을 이름을 써야하기 때문에 당신은 인라인 할 수없고 어떤 사람들은 그것을 폐쇄로부터 실격시키는 것이라고 말할 것입니다. –

답변

280

, 당신은 $ 통과 나는이 간단한 방법이 될하지 않을 수 있습니다 알고있는 참조

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

+1, http : //php100.wordpress도 참조하십시오. .com/2009/04/13/php-y-combinator/ – user187291

+0

이상한 BC 개체는 항상 참조로 전달되어야하며 anon이어야합니다. 함수는 객체입니다 ... – ellabeauty

+20

$ factorial이 전달 된 시간에 @ellabeauty는 여전히 null (정의되지 않음)이므로 참조로 전달해야합니다. 함수를 호출하기 전에 $ factorial을 수정하면 결과가 참조로 전달 될 때 변경된다는 점에 유의하십시오. –

22

로 팩토리얼 필요하지만 함수형 언어에서 "fix"이라는 기술에 대해 배웠습니다. 하스켈의 fix 함수는 가장 일반적으로 Y combinator으로 알려져 있으며 가장 잘 알려진 fixed point combinators 중 하나입니다.

고정 소수점 함수에 의해 변경되지 않은 값이다 함수 F 고정 점은 어떤 X되도록   X = F이다   (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는 자동으로 curry 함수가 아니기 때문에 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 결합 자 (Y combinator)는 실행 가능한 접근 방식입니다.

+8

'call_user_func_array()'가 크리스마스처럼 느리다는 사실은 주목할 가치가 있습니다. – Xeoncross

+10

@Xeoncross 토지 속력 기록을 세우는 PHP의 나머지 부분과 반대로? : P –

+1

참고, 이제는 (5.6+)'call_user_func_array' 대신에 인자 언 패킹을 사용할 수 있습니다. –

2

실용적인 용도는 아니지만 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) 
0

PHP의 최신 버전에서는이 작업을 수행 할 수 있습니다

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

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

이 잠재적으로 이상한 행동으로 이어질 수 있습니다.