फ़ंक्शन संरचना (कंप्यूटर विज्ञान)

From Vigyanwiki
Revision as of 18:15, 20 July 2023 by alpha>Indicwiki (Created page with "{{Short description|Programming mechanism}} {{confused|object composition}} कंप्यूटर विज्ञान में, फ़ंक्शन संरच...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

कंप्यूटर विज्ञान में, फ़ंक्शन संरचना अधिक जटिल सबरूटीन्स बनाने के लिए सरल सबरूटीन्स को संयोजित करने का एक कार्य या तंत्र है। गणित में सामान्य फ़ंक्शन संरचना की तरह, प्रत्येक फ़ंक्शन का परिणाम अगले के तर्क के रूप में पारित किया जाता है, और अंतिम का परिणाम संपूर्ण का परिणाम होता है।

प्रोग्रामर अक्सर फ़ंक्शंस को अन्य फ़ंक्शंस के परिणामों पर लागू करते हैं, और लगभग सभी प्रोग्रामिंग भाषाएं इसकी अनुमति देती हैं। कुछ मामलों में, फ़ंक्शंस की संरचना अपने आप में एक फ़ंक्शन के रूप में दिलचस्प होती है, जिसका उपयोग बाद में किया जा सकता है। ऐसे फ़ंक्शन को हमेशा परिभाषित किया जा सकता है लेकिन प्रथम श्रेणी फ़ंक्शन वाली भाषाएं इसे आसान बनाती हैं।

कार्यों को आसानी से बनाने की क्षमता रखरखाव और कोड के पुन: उपयोग के लिए फैक्टरिंग (कंप्यूटर विज्ञान) (अलग करना) सबरूटीन्स को प्रोत्साहित करती है। अधिक सामान्यतः, संपूर्ण प्रोग्रामों की रचना करके बड़े सिस्टम बनाए जा सकते हैं।

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

फ़ंक्शन कॉल कंपोज़ करना

उदाहरण के लिए, मान लीजिए हमारे पास दो फ़ंक्शन हैं (गणित) f और g, के रूप में z = f(y) और y = g(x). उन्हें लिखने का मतलब है कि हम पहले गणना करते हैं y = g(x), और फिर उपयोग करें y गणना करना z = f(y). यहाँ C (प्रोग्रामिंग भाषा) में उदाहरण दिया गया है:

float x, y, z;
// ...
y = g(x);
z = f(y);

यदि हम मध्यवर्ती परिणाम को कोई नाम नहीं देते हैं तो चरणों को जोड़ा जा सकता है:

z = f(g(x));

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

स्टैक-आधारित भाषा में, कार्यात्मक संरचना और भी अधिक स्वाभाविक है: यह संयोजन द्वारा किया जाता है, और आमतौर पर प्रोग्राम डिज़ाइन की प्राथमिक विधि है। फोर्थ (प्रोग्रामिंग भाषा) में उपरोक्त उदाहरण:

जी एफ

जो पहले स्टैक पर जो कुछ भी था उसे ले लेगा, g लागू करेगा, फिर f, और परिणाम स्टैक पर छोड़ देगा। संबंधित गणितीय नोटेशन के लिए फ़ंक्शन संरचना#वैकल्पिक नोटेशन देखें।

फ़ंक्शंस की संरचना का नामकरण

अब मान लीजिए कि g() के परिणाम पर f() को कॉल करने का संयोजन अक्सर उपयोगी होता है, और जिसे हम foo() नाम देना चाहते हैं ताकि इसे अपने आप में एक फ़ंक्शन के रूप में उपयोग किया जा सके।

अधिकांश भाषाओं में, हम रचना द्वारा कार्यान्वित एक नए फ़ंक्शन को परिभाषित कर सकते हैं। C (प्रोग्रामिंग भाषा) में उदाहरण:

float foo(float x) {
    return f(g(x));
}

(मध्यवर्ती के साथ लंबा फॉर्म भी काम करेगा।) फोर्थ में उदाहरण (प्रोग्रामिंग भाषा):

  : फू जी एफ ;

सी (प्रोग्रामिंग भाषा) जैसी भाषाओं में, एक नया फ़ंक्शन बनाने का एकमात्र तरीका इसे प्रोग्राम स्रोत में परिभाषित करना है, जिसका अर्थ है कि फ़ंक्शन को रन टाइम (प्रोग्राम जीवनचक्र चरण) पर नहीं बनाया जा सकता है। हालाँकि, पूर्वनिर्धारित कार्यों की मनमानी संरचना का मूल्यांकन संभव है:

#include <stdio.h>

typedef int FXN(int);

int f(int x) { return x+1; }
int g(int x) { return x*2; }
int h(int x) { return x-3; }

int eval(FXN *fs[], int size, int x)
{
   for (int i=0; i<size; i++) x = (*fs[i])(x);

   return x;
}

int main()
{
   // ((6+1)*2)-3 = 11
   FXN *arr[] = {f,g,h};
   printf("%d\n", eval(arr, 3, 6));

   // ((6-3)*2)+1 = 7
   arr[2] = f;  arr[0] = h;
   printf("%d\n", eval(arr, 3, 6));
}


प्रथम श्रेणी की रचना

कार्यात्मक प्रोग्रामिंग भाषाओं में, फ़ंक्शन संरचना को स्वाभाविक रूप से उच्च-क्रम फ़ंक्शन या ऑपरेटर के रूप में व्यक्त किया जा सकता है। अन्य प्रोग्रामिंग भाषाओं में आप फ़ंक्शन संरचना निष्पादित करने के लिए अपना स्वयं का तंत्र लिख सकते हैं।

हास्केल

हास्केल (प्रोग्रामिंग भाषा) में, उदाहरण foo = f  ∘  g ऊपर दिया गया है:

फू = एफ . जी

अंतर्निहित कंपोजिशन ऑपरेटर (.) का उपयोग करके जिसे जी के बाद एफ के रूप में पढ़ा जा सकता है या एफ के साथ जी बनाया जा सकता है।

रचना संचालक  ∘   को लैम्ब्डा कैलकुलस का उपयोग करके हास्केल में परिभाषित किया जा सकता है:

(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)

पहली पंक्ति (.) के प्रकार का वर्णन करती है - यह कार्यों की एक जोड़ी लेती है, f,  g और एक फ़ंक्शन लौटाता है (दूसरी पंक्ति पर लैम्ब्डा अभिव्यक्ति)। ध्यान दें कि हास्केल को एफ और जी के सटीक इनपुट और आउटपुट प्रकारों के विनिर्देश की आवश्यकता नहीं है; ए, बी, सी, और एक्स प्लेसहोल्डर हैं; केवल बीच का संबंध f,  g मायने रखता है (एफ को स्वीकार करना होगा कि जी क्या लौटाता है)। यह (.) को एक बहुरूपता (कंप्यूटर विज्ञान) ऑपरेटर बनाता है।

लिस्प

लिस्प (प्रोग्रामिंग भाषा) के वेरिएंट, विशेष रूप से स्कीम (प्रोग्रामिंग भाषा), कार्यों के उपचार के साथ समलिंगी एक विविध रचनाकार ऑपरेटर की पुनरावर्ती परिभाषा के लिए खुद को बहुत अच्छी तरह से उधार देते हैं।

(define (compose . fs)
  (if (null? fs) (lambda (x) x) ; if no argument is given, evaluates to the identity function
      (lambda (x) ((car fs) ((apply compose (cdr fs)) x)))))

; examples
(define (add-a-bang str)
  (string-append str "!"))

(define givebang
  (compose string->symbol add-a-bang symbol->string))

(givebang 'set) ; ===> set!

; anonymous composition
((compose sqrt negate square) 5) ; ===> 0+5i


एपीएल

एपीएल (प्रोग्रामिंग भाषा) की कई बोलियाँ प्रतीक का उपयोग करके फ़ंक्शन संरचना में निर्मित होती हैं . यह उच्च-क्रम फ़ंक्शन फ़ंक्शन संरचना को बाईं ओर के फ़ंक्शन के Arity#Binary अनुप्रयोग तक विस्तारित करता है A f∘g B है A f g B.

foofg

इसके अतिरिक्त, आप फ़ंक्शन संरचना को परिभाषित कर सकते हैं:

o{⍺⍺ ⍵⍵ }

ऐसी बोली में जो ब्रेसिज़ का उपयोग करके इनलाइन परिभाषा का समर्थन नहीं करती है, पारंपरिक परिभाषा उपलब्ध है:

 r(f o g)x
  rf g x


राकू

हास्केल (प्रोग्रामिंग भाषा) की तरह राकू (प्रोग्रामिंग भाषा) में एक अंतर्निहित फ़ंक्शन कंपोज़िशन ऑपरेटर है, मुख्य अंतर यह है कि इसे इस प्रकार लिखा जाता है या o.

my &foo = &f  &g;

इसके अलावा हास्केल (प्रोग्रामिंग भाषा) की तरह आप ऑपरेटर को स्वयं परिभाषित कर सकते हैं। वास्तव में निम्नलिखित Raku कोड है जिसका उपयोग Rakudo कार्यान्वयन में इसे परिभाषित करने के लिए किया जाता है।

# the implementation has a slightly different line here because it cheats
proto sub infix:<∘> (&?, &?) is equiv(&[~]) is assoc<left> {*}

multi sub infix:<∘> () { *.self } # allows `[∘] @array` to work when `@array` is empty
multi sub infix:<∘> (&f) { &f }   # allows `[∘] @array` to work when `@array` has one element
multi sub infix:<∘> (&f, &g --> Block) {
    (&f).count > 1
    ?? -> |args { f |g |args }
    !! -> |args { f g |args }
}

# alias it to the "Texas" spelling ( everything is bigger, and ASCII in Texas )
my &infix:<o> := &infix:<∘>;


पायथन

पायथन (प्रोग्रामिंग भाषा) में, फ़ंक्शंस के किसी भी समूह के लिए संरचना को परिभाषित करने का एक तरीका, फ़ोल्ड (उच्च-क्रम फ़ंक्शन) फ़ंक्शन का उपयोग करना है (पायथन 3 में functools.reduce का उपयोग करें):

# Available since Python v2.6
from functools import reduce

def compose(*funcs) -> int:
    """Compose a group of functions (f(g(h(...)))) into a single composite func."""
    return reduce(lambda f, g: lambda x: f(g(x)), funcs)

# Example
f = lambda x: x + 1
g = lambda x: x * 2
h = lambda x: x - 3

# Call the function x=10 : ((x-3)*2)+1 = 15
print(compose(f, g, h)(10))


जावास्क्रिप्ट

जावास्क्रिप्ट में हम इसे एक फ़ंक्शन के रूप में परिभाषित कर सकते हैं जो दो फ़ंक्शन f और g लेता है, और एक फ़ंक्शन उत्पन्न करता है:

function o(f, g) {
    return function(x) {
        return f(g(x));
    }
}

// Alternatively, using the rest operator and lambda expressions in ES2015
const compose = (...fs) => (x) => fs.reduceRight((acc, f) => f(acc), x)


सी#

C_Sharp_(प्रोग्रामिंग_भाषा)|C# में हम इसे एक एक्सटेंशन विधि के रूप में परिभाषित कर सकते हैं जो Funcs f और g लेता है, और एक नया Func तैयार करता है:

// Call example:
//   var c = f.ComposeWith(g);
//
//   Func<int, bool> g = _ => ...
//   Func<bool, string> f = _ => ...

public static Func<T1, T3> ComposeWith<T1, T2, T3>(this Func<T2, T3> f, Func<T1, T2> g) => x => f(g(x));


रूबी

रूबी (प्रोग्रामिंग भाषा) जैसी भाषाएँ आपको स्वयं एक बाइनरी ऑपरेटर बनाने देती हैं:

class Proc
  def compose(other_fn)
    ->(*as) { other_fn.call(call(*as)) }
  end
  alias_method :+, :compose
end

f = ->(x) { x * 2 }
g = ->(x) { x ** 3 }
(f + g).call(12) # => 13824

हालाँकि, रूबी 2.6 में एक मूल फ़ंक्शन कंपोज़िशन ऑपरेटर पेश किया गया था:[3]

f = proc{|x| x + 2}
g = proc{|x| x * 3}
(f << g).call(3) # -> 11; identical to f(g(3))
(f >> g).call(3) # -> 15; identical to g(f(3))


अनुसंधान सर्वेक्षण

रचनाशीलता और रचनाशीलता के सिद्धांत सहित रचना की धारणाएं इतनी सर्वव्यापी हैं कि अनुसंधान के कई पहलू अलग-अलग विकसित हुए हैं। निम्नलिखित उस प्रकार के शोध का एक नमूना है जिसमें रचना की धारणा केंद्रीय है।

  • Steele (1994) हास्केल (प्रोग्रामिंग भाषा) में 'मोनैड (कार्यात्मक प्रोग्रामिंग)' के रूप में जाने जाने वाले बिल्डिंग ब्लॉक्स के संयोजन में फ़ंक्शन संरचना को सीधे लागू किया जाता है।
  • Meyer (1988) ने कंपोजिबिलिटी के संदर्भ में कोड के पुन: उपयोग की समस्या को संबोधित किया।
  • Abadi & Lamport (1993) औपचारिक रूप से कार्यात्मक संरचना के लिए एक प्रमाण नियम परिभाषित किया गया है जो प्रोग्राम की सुरक्षा और जीवंतता का आश्वासन देता है।
  • Kracht (2001) इसे कम्प्यूटेशनल सांकेतिकता प्रणाली में रखकर और कम्प्यूटेशनल भाषाविज्ञान में अक्सर सामने आने वाली संरचनात्मक अस्पष्टता की समस्या पर लागू करके संरचना के एक मजबूत रूप की पहचान की।
  • van Gelder & Port (1993) प्राकृतिक भाषा प्रसंस्करण के अनुरूप पहलुओं में संरचना की भूमिका की जांच की गई।
  • द्वारा एक समीक्षा के अनुसार Gibbons (2002), रचना का औपचारिक उपचार जावा (प्रोग्रामिंग भाषा) भाषा के लिए आईबीएम की विज़ुअल एज जैसी दृश्य प्रोग्रामिंग भाषाओं में घटक असेंबली के सत्यापन को रेखांकित करता है।

बड़े पैमाने की रचना

संपूर्ण प्रोग्राम या सिस्टम को फ़ंक्शंस के रूप में माना जा सकता है, जिन्हें आसानी से बनाया जा सकता है यदि उनके इनपुट और आउटपुट अच्छी तरह से परिभाषित हों।[4] फ़िल्टर (सॉफ़्टवेयर) की आसान संरचना की अनुमति देने वाली पाइपलाइन (सॉफ़्टवेयर) इतनी सफल रहीं कि वे ऑपरेटिंग सिस्टम की पाइपलाइन (सॉफ़्टवेयर) बन गईं।

साइड इफेक्ट्स के साथ अनिवार्य प्रोग्रामिंग संदर्भात्मक पारदर्शिता का उल्लंघन करती है और इसलिए साफ-सुथरी रचना योग्य नहीं है। हालाँकि, यदि कोई कोड को इनपुट और आउटपुट के रूप में चलाने से पहले और बाद में दुनिया की स्थिति पर विचार करता है, तो उसे एक क्लीन फ़ंक्शन मिलता है। ऐसे कार्यों की संरचना प्रक्रियाओं को एक के बाद एक चलाने से मेल खाती है। मोनाड (कार्यात्मक प्रोग्रामिंग) औपचारिकता इस विचार का उपयोग साइड इफेक्ट्स और इनपुट/आउटपुट (आई/ओ) को कार्यात्मक भाषाओं में शामिल करने के लिए करती है।

यह भी देखें

टिप्पणियाँ

  1. Cox (1986), pp. 15–17
  2. DeMarco & Lister (1995), pp. 133–135.
  3. "Ruby 2.6.0 Released". www.ruby-lang.org. Retrieved 2019-01-04.
  4. Raymond (2003)


संदर्भ