अनाम पुनरावर्ती PHP फ़ंक्शन


198

क्या एक PHP फ़ंक्शन करना संभव है जो पुनरावर्ती और अनाम दोनों है? यह काम करने के लिए मेरा प्रयास है, लेकिन यह फ़ंक्शन नाम में पारित नहीं होता है।

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

मुझे यह भी पता है कि यह फैक्टरियल को लागू करने का एक बुरा तरीका है, यह सिर्फ एक उदाहरण है।


मेरे पास जाँच करने के लिए PHP 5.3.0 नहीं है लेकिन क्या आपने उपयोग करने का प्रयास किया है global $factorial?
kennytm

5
(sidenote) एक लांबा एक अनाम फ़ंक्शन है, जबकि ऊपर एक क्लोजर है।
गॉर्डन

1
लैम्ब्डा और क्लोसुर परस्पर अनन्य नहीं हैं। वास्तव में कुछ लोगों का मानना ​​है कि एक क्लोजर के लिए एक क्लोजर (अनाम फ़ंक्शन) होना आवश्यक है। उदाहरण के लिए पायथन को आप फ़ंक्शन को पहले नाम (संस्करण के आधार पर) देना चाहते हैं। क्योंकि आपको इसे एक ऐसा नाम देना होगा जिसे आप इनलाइन नहीं कर सकते हैं और कुछ कहेंगे कि यह एक बंद होने से अयोग्य है।
एडम गेंट

1
print $factorial( 0);
निकब

php मैनुअल उदाहरण

जवाबों:


357

इसे काम करने के लिए, आपको संदर्भ के रूप में $ फैक्टोरियल पास करना होगा

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

यह अजीब बीसी वस्तुओं को हमेशा संदर्भ और एनोन द्वारा पारित किया जाना चाहिए। कार्य वस्तुएं हैं ...
ellabeauty

25
उस समय $ फैक्टोरियल बीतने पर @ellabeauty, यह अभी भी अशक्त (परिभाषित नहीं) है, इसीलिए आपको इसे संदर्भ के साथ पारित करना होगा। ज्ञात हो, कि यदि आप फ़ंक्शन को कॉल करने से पहले $ फ़ैक्टोरियल को संशोधित करते हैं, तो परिणाम बदल जाएगा क्योंकि यह संदर्भ द्वारा पारित हो गया है।
मारियस बाल्कीटिस

9
@ellabeauty: नहीं, आप इसे पूरी तरह से गलत समझते हैं। &मूल्य के बिना सब कुछ है। &संदर्भ के साथ सब कुछ है। PHP5 में "ऑब्जेक्ट" मान नहीं हैं और इन्हें असाइन या पास नहीं किया जा सकता है। आप एक चर के साथ काम कर रहे हैं जिसका मूल्य एक वस्तु संदर्भ है। सभी चरों की तरह, यह मान के आधार पर या संदर्भ द्वारा कैप्चर किया जा सकता है कि क्या कोई है &
newacct

3
होश उड़ जाना! आपका बहुत बहुत धन्यवाद! मुझे अब तक इस बारे में कैसे पता नहीं चला? पुनरावर्ती अनाम कार्यों के लिए मेरे पास आवेदन की मात्रा बहुत बड़ी है। अब मैं अंत में लेआउट में नेस्टेड संरचनाओं के माध्यम से लूप कर सकता हूं बिना किसी विधि को स्पष्ट रूप से परिभाषित करने के और अपने सभी लेआउट डेटा को मेरी कक्षाओं से बाहर रखने के लिए।
डाइटर ग्रिबिट्ज

जैसे @barius ने कहा, जब इसे फोर्क में इस्तेमाल किया जाता है तो सावधानी बरतें। $factorialफ़ंक्शन को कॉल करने से पहले बदल दिया जाएगा और यह अजीब व्यवहार के साथ हो सकता है।
stil

24

मुझे पता है कि यह एक सरल दृष्टिकोण नहीं हो सकता है, लेकिन मैंने कार्यात्मक भाषाओं से "फिक्स" नामक तकनीक के बारे में सीखा । fixहास्केल से समारोह के रूप में अधिक आम तौर पर जाना जाता है Y Combinator , जो सबसे प्रसिद्ध में से एक है निश्चित बिंदु combinators

एक निश्चित बिंदु एक ऐसा मान है जो किसी फ़ंक्शन द्वारा अपरिवर्तित होता है: फ़ंक्शन f का एक निश्चित बिंदु कोई भी x ऐसा x = f (x) है। एक निश्चित बिंदु कॉम्बिनेटर y एक फ़ंक्शन है जो किसी भी फ़ंक्शन f के लिए एक निश्चित बिंदु देता है। चूँकि y (f) f का एक निश्चित बिंदु है, इसलिए हमारे पास y (f) = f (y (f)) है।

अनिवार्य रूप से, वाई कॉम्बिनेटर एक नया फ़ंक्शन बनाता है जो मूल के सभी तर्कों को लेता है, साथ ही एक अतिरिक्त तर्क जो पुनरावर्ती फ़ंक्शन है। यह कैसे काम करता है यह स्पष्ट संकेतन का उपयोग करके अधिक स्पष्ट है। कोष्ठक ( f(x,y,...)) में तर्क लिखने के बजाय , फ़ंक्शन के बाद उन्हें लिखें f x y ...:। वाई कॉम्बिनेटर के रूप में परिभाषित किया गया है Y f = f (Y f); या, पुनरावर्ती फ़ंक्शन के लिए एकल तर्क के साथ Y f x = f (Y f) x,।

चूंकि पीएचपी स्वचालित रूप से नहीं करता करी काम करता है, इसे बनाने के लिए एक हैक का एक सा 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 के लिए क्लोजर विधि अधिक उपयुक्त है (जो कि बहुत कार्यात्मक भाषा नहीं है), मूल समस्या उत्पादन के लिए व्यायाम से अधिक है, इसलिए वाई कॉम्बिनेटर एक व्यवहार्य दृष्टिकोण है।


10
यह ध्यान देने योग्य है कि call_user_func_array()क्रिसमस के रूप में धीमा है।
एक्सोनक्रॉस

11
@Xeoncross बाकी PHP के विपरीत जो भूमि की गति रिकॉर्ड स्थापित कर रहा है? : पी
केंडल हॉपकिंस

1
ध्यान दें, आप अब (5.6+) के बजाय तर्क अनपैकिंग का उपयोग कर सकते हैं call_user_func_array
फाबिएन सा

@KendallHopkins क्यों यह अतिरिक्त तर्क array_unshift( $args, fix($func) );? आर्ग पहले से ही मापदंडों से लदे हुए हैं, और वास्तविक पुनरावृत्ति call_user_func_array () द्वारा किया जाता है, तो वह रेखा क्या करती है?
मैं चाहता हूं कि उत्तर

5

यद्यपि यह व्यावहारिक उपयोग के लिए नहीं है, सी-स्तरीय एक्सटेंशन 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();

इससे संभावित रूप से अजीब व्यवहार हो सकता है।


0

आप नीचे के रूप में 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


0

एक अनाम वर्ग (PHP 7+) के साथ, एक चर को परिभाषित किए बिना:

echo (new class {
    function __invoke($n) {
        return $n < 2 ? 1 : $n * $this($n - 1);
    }
})(5);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.