क्या फ़ंक्शनल प्रोग्रामिंग में जेनरेटर फ़ंक्शंस मान्य हैं?


17

प्रश्न हैं:

  • क्या जनरेटर कार्यात्मक प्रोग्रामिंग प्रतिमान को तोड़ते हैं? क्यों या क्यों नहीं?
  • यदि हाँ, तो क्या कार्यात्मक प्रोग्रामिंग में जनरेटर का उपयोग किया जा सकता है और कैसे?

निम्नलिखित को धयान मे रखते हुए:

function * downCounter(maxValue) {
  yield maxValue;
  yield * downCounter(maxValue > 0 ? maxValue - 1 : 0);
}

let counter = downCounter(26);
counter.next().value; // 26
counter.next().value; // 25
// ...etc

downCounterविधि राज्यविहीन प्रकट होता है। साथ ही, downCounterएक ही इनपुट के साथ कॉल करना, हमेशा एक ही आउटपुट में परिणाम देगा। हालांकि, एक ही समय में, कॉलिंग next()लगातार परिणाम नहीं देता है।

मैं अनिश्चित हूं कि क्या जनरेटर कार्यात्मक प्रोग्रामिंग प्रतिमान को तोड़ते हैं या नहीं क्योंकि इस उदाहरण counterमें एक जनरेटर ऑब्जेक्ट है और इसलिए कॉलिंग next()उसी परिणाम का उत्पादन करेगी जैसे कि एक अन्य जनरेटर ऑब्जेक्ट बिल्कुल उसी के साथ बनाया गया है maxValue

साथ ही, someCollection[3]सरणी पर कॉल करने से हमेशा चौथा तत्व वापस आ जाएगा। इसी तरह, next()जनरेटर ऑब्जेक्ट पर चार बार कॉल करने पर भी हमेशा चौथा तत्व वापस आ जाएगा।

अधिक संदर्भ के लिए, प्रोग्रामिंग काटा पर काम करते समय ये प्रश्न उठाए गए थे । जिस व्यक्ति ने सवाल का जवाब दिया, उसने सवाल उठाया कि क्या कार्यात्मक प्रोग्रामिंग में जनरेटर का उपयोग किया जा सकता है या नहीं और वे राज्य को धारण करते हैं या नहीं।


2
हर कार्यक्रम में राज्य होता है। असली सवाल यह है कि क्या यह कार्यात्मक राज्य के रूप में योग्य है , जिसे मैं "अपरिवर्तनीय राज्य" के रूप में व्याख्या करता हूं, जो राज्य एक बार सौंपा जाने के बाद नहीं बदलता है। मेरा दावा है कि यदि आप एक कॉल पर एक जनरेटर रिटर्न कुछ अलग कर सकते हैं तो यह है कि उत्परिवर्तित स्थिति किसी तरह शामिल है।
रॉबर्ट हार्वे

जवाबों:


14

जनरेटर के कार्य विशेष रूप से विशेष नहीं हैं। हम कॉलबैक-आधारित शैली में जनरेटर फ़ंक्शन को फिर से लिखकर एक समान तंत्र को लागू कर सकते हैं:

function downCounter(maxValue) {
  return {
    "value": maxValue,
    "next": function () {
      return downCounter(maxValue > 0 ? maxValue - 1 : 0);
     },
  };
}

let counter = downCounter(26);
counter.value; //=> 26
counter.next().value; //=> 25

स्पष्ट रूप से, downCounterयह उतना ही शुद्ध और कार्यात्मक है जितना इसे मिलता है। यहां कोई मुद्दा नहीं है।

जावास्क्रिप्ट द्वारा उपयोग किए जाने वाले जनरेटर प्रोटोकॉल में एक परिवर्तनशील वस्तु शामिल है। यह आवश्यक नहीं है, उपरोक्त कोड देखें। विशेष रूप से, परिवर्तनशील वस्तुओं का मतलब है कि हम संदर्भात्मक पारदर्शिता को ढीला करते हैं - किसी अभिव्यक्ति को उसके मूल्य से बदलने की क्षमता। मेरे उदाहरण में, हमेशा कोई फर्क नहीं पड़ता कि यह कहां होता है और कितनी बार हम इसे दोहराते हैं, का मूल्यांकन counter.next().valueकरेंगे , यह जेएस जनरेटर के साथ ऐसा नहीं है - एक बिंदु पर यह तब है , और यह वास्तव में कोई भी संख्या हो सकती है। यह समस्याग्रस्त है यदि हम किसी अन्य फ़ंक्शन के लिए जनरेटर का संदर्भ देते हैं:252625

counter.next().value; //=> 25
otherFunction(counter); // does this consume the counter?
counter.next().value; // what will this be? It depends on the otherFunction()

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

वैसे, हास्केल में सूची और जनरेटर को वापस करने के बीच कोई अंतर नहीं है, क्योंकि यह आलसी मूल्यांकन का उपयोग करता है:

downCounter :: Int -> [Int]
downCounter maxValue =
  maxValue : (downCounter (max 0 (maxValue - 1)))
-- invoke as "take n (downCounter 26)" to display n elements
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.