क्रियात्मक सोच। भाग 7

हम F # में कार्यात्मक प्रोग्रामिंग पर लेखों की अपनी श्रृंखला जारी रखते हैं। आज हमारे पास एक बहुत ही दिलचस्प विषय है: कार्यों की परिभाषा। सहित, चलो अनाम कार्यों, मापदंडों के बिना कार्यों, पुनरावर्ती कार्यों, संयोजन, और बहुत कुछ के बारे में बात करते हैं। बिल्ली के नीचे देखो!




कार्य की परिभाषा


हम पहले से ही जानते हैं कि "लेट" सिंटैक्स का उपयोग करके नियमित फ़ंक्शन कैसे बनाएं:


let add xy = x + y 

इस लेख में, हम कार्यों को बनाने के कुछ अन्य तरीकों पर ध्यान देंगे, साथ ही उन्हें परिभाषित करने के लिए सुझाव भी देंगे।


बेनामी फ़ंक्शंस (लंबोदर)


यदि आप अन्य भाषाओं में लैम्ब्डा से परिचित हैं, तो निम्नलिखित पैराग्राफ परिचित होंगे। बेनामी फ़ंक्शंस (या "लैम्ब्डा एक्सप्रेशन") को निम्नानुसार परिभाषित किया गया है:


 fun parameter1 parameter2 etc -> expression 

C # से लंबोदर की तुलना में, दो अंतर हैं:


  • lambdas को fun कीवर्ड से शुरू करना चाहिए, जो C # में आवश्यक नहीं है
  • एकल तीर -> उपयोग किया जाता है -> , सी # से डबल => बजाय।

अतिरिक्त समारोह की लम्बे परिभाषा:


 let add = fun xy -> x + y 

पारंपरिक रूप में एक ही कार्य:


 let add xy = x + y 

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


 //    let add1 i = i + 1 [1..10] |> List.map add1 //        [1..10] |> List.map (fun i -> i + 1) 

ध्यान दें कि कोष्ठक का उपयोग लंबोदर के आसपास किया जाना चाहिए।


लम्बेदा का उपयोग तब किया जाता है जब स्पष्ट रूप से अलग फ़ंक्शन की आवश्यकता होती है। उदाहरण के लिए, पहले चर्चा की गई " adderGenerator ", जिसे हमने पहले चर्चा की थी, को लैम्ब्डा का उपयोग करके फिर से लिखा जा सकता है।


 //   let adderGenerator x = (+) x //     let adderGenerator x = fun y -> x + y 

लैम्ब्डा संस्करण थोड़ा लंबा है, लेकिन तुरंत यह स्पष्ट करता है कि एक मध्यवर्ती फ़ंक्शन वापस आ जाएगा।


लंबोदर को घोंसला दिया जा सकता है। एक adderGenerator परिभाषा का एक और उदाहरण, इस बार केवल adderGenerator पर।


 let adderGenerator = fun x -> (fun y -> x + y) 

क्या आप स्पष्ट हैं कि सभी तीन परिभाषाएँ समान हैं?


 let adderGenerator1 xy = x + y let adderGenerator2 x = fun y -> x + y let adderGenerator3 = fun x -> (fun y -> x + y) 

यदि नहीं, तो अध्याय को फिर से पढ़ने पर पढ़ें । यह समझने के लिए बहुत महत्वपूर्ण है!


पैटर्न मिलान


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


निम्न उदाहरण फ़ंक्शन परिभाषा में पैटर्न के उपयोग को दर्शाता है:


 type Name = {first:string; last:string} //    let bob = {first="bob"; last="smith"} //   //     let f1 name = //   let {first=f; last=l} = name //     printfn "first=%s; last=%s" fl //   let f2 {first=f; last=l} = //        printfn "first=%s; last=%s" fl //  f1 bob f2 bob 

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


 let f3 (x::xs) = //       printfn "first element is=%A" x 

कंपाइलर अपूर्ण मिलान के बारे में एक चेतावनी देगा (एक खाली सूची इस फ़ंक्शन के प्रवेश द्वार पर रनटाइम में त्रुटि का कारण बनेगी)।


सामान्य गलती: टुपल्स बनाम। कई मापदंडों


यदि आप एक सी-लाइक भाषा से आते हैं, तो फ़ंक्शन के एकमात्र तर्क के रूप में उपयोग किया जाने वाला ट्यूपल बहु-पैरामीटर फ़ंक्शन से दर्दनाक रूप से मिल सकता है। लेकिन यह एक ही बात नहीं है! जैसा कि मैंने पहले उल्लेख किया है, यदि आप एक अल्पविराम देखते हैं, तो यह सबसे अधिक संभावना है। पैरामीटर रिक्त स्थान से अलग हो जाते हैं।


भ्रम का उदाहरण:


 //      let addTwoParams xy = x + y //      -  let addTuple aTuple = let (x,y) = aTuple x + y //         //        let addConfusingTuple (x,y) = x + y 

  • पहली परिभाषा, " addTwoParams ", दो मापदंडों को लेता है, एक स्थान द्वारा अलग किया गया।
  • दूसरी परिभाषा, " addTuple ", एक पैरामीटर लेता है। यह पैरामीटर टपल से "x" और "y" को बांधता है और उन्हें सम्‍मिलित करता है।
  • तीसरी परिभाषा, " addConfusingTuple ", " addConfusingTuple " की तरह एक पैरामीटर लेता है, लेकिन ट्रिक यह है कि यह tuple addTuple (पैटर्न से मेल खाता हुआ) है और मिलान मिलान का उपयोग करके पैरामीटर परिभाषा के हिस्से के रूप में बाध्य है। पर्दे के पीछे, सब कुछ वैसा ही होता है, जैसा कि addTuple में addTuple

आइए हस्ताक्षर देखें (हमेशा उन्हें देखें यदि आप कुछ के बारे में निश्चित नहीं हैं)।


 val addTwoParams : int -> int -> int //   val addTuple : int * int -> int // tuple->int val addConfusingTuple : int * int -> int // tuple->int 

और अब यहाँ:


 // addTwoParams 1 2 // ok --      addTwoParams (1,2) // error -     // => error FS0001: This expression was expected to have type // int but here has type 'a * 'b 

यहाँ हम दूसरी कॉल में एक त्रुटि देखते हैं।


सबसे पहले, कंपाइलर (1,2) रूप के सामान्यीकृत टपल ('a * 'b) (1,2) रूप में व्यवहार करता है, जिसे वह " addTwoParams " के पहले पैरामीटर के रूप में पारित करने की कोशिश करता है। जिसके बाद वह शिकायत करता है कि अपेक्षित पहला पैरामीटर addTwoParams int नहीं है, लेकिन एक टपल पास करने का प्रयास किया गया था।


टपल बनाने के लिए, अल्पविराम का उपयोग करें!


 addTuple (1,2) // ok addConfusingTuple (1,2) // ok let x = (1,2) addTuple x // ok let y = 1,2 //  , //  ! addTuple y // ok addConfusingTuple y // ok 

और इसके विपरीत, यदि आप एक कार्य के लिए कई तर्कों को पारित करते हैं, जो कि टपल का इंतजार कर रहे हैं, तो आपको एक अयोग्य त्रुटि भी मिलती है।


 addConfusingTuple 1 2 // error --          // => error FS0003: This value is not a function and // cannot be applied 

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


ट्यूपल्स को मापदंडों के रूप में क्यों नहीं उपयोग किया जाता है?


ऊपर ट्यूपल्स की चर्चा कई मापदंडों के साथ कार्यों को परिभाषित करने का एक और तरीका दिखाती है: उन्हें अलग से पारित करने के बजाय, सभी मापदंडों को एक संरचना में इकट्ठा किया जा सकता है। नीचे दिए गए उदाहरण में, फ़ंक्शन एकल पैरामीटर लेता है - तीन तत्वों का एक टपल।


 let f (x,y,z) = x + y * z //  - int * int * int -> int //  f (1,2,3) 

यह ध्यान दिया जाना चाहिए कि हस्ताक्षर तीन मापदंडों के साथ एक फ़ंक्शन के हस्ताक्षर से अलग है। टपल (int*int*int) ओर इशारा करते हुए केवल एक तीर, एक पैरामीटर और तारांकन हैं।


जब अलग-अलग मापदंडों के साथ तर्क प्रस्तुत करना आवश्यक है, और कब एक टुपल?


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

विशेष मामला: .NET लाइब्रेरी टुपल्स और फ़ंक्शंस


.NET पुस्तकालयों को बुलाते समय, अल्पविराम बहुत आम है!


वे सभी tuples स्वीकार करते हैं, और कॉल C # में समान दिखते हैं:


 //  System.String.Compare("a","b") //   System.String.Compare "a" "b" 

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


ध्यान दें कि ये कॉल केवल ट्यूपल्स को स्थानांतरित करने की तरह दिखते हैं, लेकिन यह वास्तव में एक विशेष मामला है। आप ऐसे कार्यों में असली tuples पास नहीं कर सकते:


 let tuple = ("a","b") System.String.Compare tuple // error System.String.Compare "a","b" // error 

यदि आप .NET फ़ंक्शंस को आंशिक रूप से लागू करना चाहते हैं, तो बस उन पर रैपर लिखें, जैसा कि पहले किया गया था , या जैसा कि नीचे दिखाया गया है:


 //    let strCompare xy = System.String.Compare(x,y) //    let strCompareWithB = strCompare "B" //      ["A";"B";"C"] |> List.map strCompareWithB 

व्यक्तिगत और समूहीकृत पैरामीटर का चयन करने के लिए गाइड


टुपल्स की चर्चा एक अधिक सामान्य विषय की ओर ले जाती है: कब मापदंडों को अलग किया जाना चाहिए, और कब समूहबद्ध किया जाना चाहिए?


आपको इस बात पर ध्यान देना चाहिए कि इस संबंध में F # C से कैसे भिन्न है। सी # में, सभी मापदंडों को हमेशा पास किया जाता है, इसलिए यह सवाल वहां भी नहीं उठता है! एफ # में, आंशिक आवेदन के कारण, केवल कुछ मापदंडों का प्रतिनिधित्व किया जा सकता है, इसलिए मामले के बीच अंतर करना आवश्यक है जब मापदंडों को संयुक्त किया जाना चाहिए और जब वे स्वतंत्र होते हैं तो मामला।


अपने स्वयं के कार्यों को डिजाइन करते समय मापदंडों की संरचना करने के बारे में सामान्य सिफारिशें।


  • सामान्य मामले में, एक संरचना को पारित करने के बजाय अलग-अलग मापदंडों का उपयोग करना हमेशा बेहतर होता है, चाहे वह एक ट्यूल या रिकॉर्ड हो। यह आंशिक अनुप्रयोग जैसे अधिक लचीले व्यवहार के लिए अनुमति देता है।
  • लेकिन, जब मापदंडों के एक समूह को एक बार में पारित करने की आवश्यकता होती है, तो किसी प्रकार के समूहीकरण तंत्र का उपयोग किया जाना चाहिए।

दूसरे शब्दों में, एक फ़ंक्शन विकसित करते समय, अपने आप से पूछें, "क्या मैं इस पैरामीटर को अलग से प्रदान कर सकता हूं?" यदि उत्तर नहीं है, तो मापदंडों को समूहीकृत किया जाना चाहिए।


आइए कुछ उदाहरण देखें:


 //     . //      ,       let add xy = x + y //         //      ,    let locateOnMap (xCoord,yCoord) = //  //      //      -     type CustomerName = {First:string; Last:string} let setCustomerName aCustomerName = //  let setCustomerName first last = //   //     //     //    ,     let setCustomerName myCredentials aName = // 

अंत में, सुनिश्चित करें कि मापदंडों का क्रम आंशिक आवेदन में मदद करेगा ( यहां मैनुअल देखें)। उदाहरण के लिए, मैंने अंतिम फ़ंक्शन में myCredentials से पहले aName क्यों रखा?


मापदंडों के बिना कार्य


कभी-कभी आपको एक फ़ंक्शन की आवश्यकता हो सकती है जो किसी भी पैरामीटर को स्वीकार नहीं करता है। उदाहरण के लिए, आपको फ़ंक्शन "हैलो वर्ल्ड" की आवश्यकता है जिसे कई बार कहा जा सकता है। जैसा कि पिछले भाग में दिखाया गया है, भोली परिभाषा काम नहीं करती है।


 let sayHello = printfn "Hello World!" //      

लेकिन यह फ़ंक्शन में एक इकाई पैरामीटर जोड़कर या लंबोदा का उपयोग करके तय किया जा सकता है।


 let sayHello() = printfn "Hello World!" //  let sayHello = fun () -> printfn "Hello World!" //  

उसके बाद, फ़ंक्शन को हमेशा unit तर्क के साथ बुलाया जाना चाहिए:


 //  sayHello() 

.NET पुस्तकालयों के साथ बातचीत करते समय अक्सर क्या होता है:


 Console.ReadLine() System.Environment.GetCommandLineArgs() System.IO.Directory.GetCurrentDirectory() 

याद रखें, उन्हें unit मापदंडों के साथ कॉल करें!


नए ऑपरेटरों को परिभाषित करना


आप एक या अधिक ऑपरेटर वर्णों का उपयोग करके कार्यों को परिभाषित कर सकते हैं (वर्णों की सूची के लिए प्रलेखन देखें):


 //  let (.*%) xy = x + y + 1 

फ़ंक्शन को परिभाषित करने के लिए आपको वर्णों के आसपास कोष्ठक का उपयोग करना चाहिए।


* शुरू होने वाले ऑपरेटरों को कोष्ठक और * बीच एक स्थान की आवश्यकता होती है, क्योंकि F # में (* टिप्पणी की शुरुआत के रूप में कार्य करता है (जैसे / #...*/ C # में):


 let ( *+* ) xy = x + y + 1 

एक बार परिभाषित करने के बाद, एक नया फ़ंक्शन सामान्य तरीके से उपयोग किया जा सकता है यदि यह कोष्ठक में लिपटा हो:


 let result = (.*%) 2 3 

यदि फ़ंक्शन दो मापदंडों के साथ उपयोग किया जाता है, तो आप कोष्ठक के बिना infix ऑपरेटर रिकॉर्ड का उपयोग कर सकते हैं।


 let result = 2 .*% 3 

तुम भी उपसर्ग ऑपरेटरों के साथ शुरू परिभाषित कर सकते हैं ! या ~ (कुछ प्रतिबंधों के साथ, दस्तावेज देखें)


 let (~%%) (s:string) = s.ToCharArray() // let result = %% "hello" 

एफ # में, बयानों को परिभाषित करना एक काफी सामान्य ऑपरेशन है, और कई पुस्तकालय >=> और <*> जैसे नामों के साथ बयानों का निर्यात करेंगे।


बिंदु मुक्त शैली


हमने पहले ही ऐसे कार्यों के कई उदाहरण देखे हैं जिनमें अराजकता के स्तर को कम करने के लिए नवीनतम मापदंडों का अभाव था। इस शैली को बिंदु-मुक्त शैली या टैसिट प्रोग्रामिंग कहा जाता है


यहाँ कुछ उदाहरण हैं:


 let add xy = x + y //  let add x = (+) x // point free let add1Times2 x = (x + 1) * 2 //  let add1Times2 = (+) 1 >> (*) 2 // point free let sum list = List.reduce (fun sum e -> sum+e) list //  let sum = List.reduce (+) // point free 

इस शैली के अपने पेशेवरों और विपक्ष हैं।


एक लाभ यह है कि निम्न-स्तरीय वस्तुओं के साथ उपद्रव के बजाय उच्च-क्रम के कार्यों की संरचना पर जोर दिया जाता है। उदाहरण के लिए, " (+) 1 >> (*) 2 " गुणा के बाद एक स्पष्ट जोड़ है। और " List.reduce (+) " यह स्पष्ट करता है कि सूची जानकारी की परवाह किए बिना अतिरिक्त संचालन महत्वपूर्ण है।


एक निरर्थक शैली आपको मूल एल्गोरिदम पर ध्यान केंद्रित करने और कोड में सामान्य सुविधाओं की पहचान करने की अनुमति देती है। ऊपर उपयोग किया गया " reduce " फ़ंक्शन एक अच्छा उदाहरण है। इस विषय पर सूची प्रसंस्करण पर एक योजनाबद्ध श्रृंखला में चर्चा की जाएगी।


दूसरी ओर, इस तरह की शैली का अत्यधिक उपयोग कोड को अस्पष्ट बना सकता है। स्पष्ट पैरामीटर प्रलेखन के रूप में कार्य करते हैं और उनके नाम (जैसे "सूची") यह समझना आसान बनाते हैं कि फ़ंक्शन क्या करता है।


प्रोग्रामिंग में सब कुछ की तरह, सबसे स्पष्ट सिफारिश उस दृष्टिकोण को पसंद करना है जो सबसे स्पष्टता प्रदान करता है।


combinators


" संयोजक " उन कार्यों को कहते हैं जिनका परिणाम केवल उनके मापदंडों पर निर्भर करता है। इसका मतलब यह है कि बाहरी दुनिया पर कोई निर्भरता नहीं है, और विशेष रूप से, कोई अन्य कार्य या वैश्विक मूल्य उन्हें प्रभावित नहीं कर सकते हैं।


व्यवहार में, इसका मतलब है कि विभिन्न तरीकों से उनके मापदंडों के संयोजन से संयोजन कार्य सीमित हैं।


हमने पहले से ही कई कॉम्बिनेटर देखे हैं: एक पाइप और एक रचना ऑपरेटर। यदि आप उनकी परिभाषाओं को देखते हैं, तो यह स्पष्ट है कि वे जो कुछ भी करते हैं वह विभिन्न तरीकों से मापदंडों को फिर से व्यवस्थित करता है।


 let (|>) xf = fx //  pipe let (<|) fx = fx //  pipe let (>>) fgx = g (fx) //   let (<<) gfx = g (fx) //   

दूसरी ओर, "प्रिंटफ" जैसे कार्य, हालांकि आदिम, दहनशील नहीं हैं, क्योंकि वे बाहरी दुनिया (I / O) पर निर्भर हैं।


संयुक्त पक्षी


कॉम्बिनेटर तर्क के एक पूरे खंड का आधार हैं (स्वाभाविक रूप से "कॉम्बीनेटरियल लॉजिक" कहा जाता है), जिसे कंप्यूटर और प्रोग्रामिंग भाषाओं से कई साल पहले आविष्कार किया गया था। कॉम्बिनेटरियल लॉजिक का कार्यात्मक प्रोग्रामिंग पर बहुत बड़ा प्रभाव है।


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


 let I x = x //  ,  Idiot bird let K xy = x // the Kestrel let M x = x >> x // the Mockingbird let T xy = yx // the Thrush ( !) let Q xyz = y (xz) // the Queer bird ( !) let S xyz = xz (yz) // The Starling //   ... let rec Y fx = f (Y f) x // Y-,  Sage bird 

अक्षर के नाम काफी मानक हैं, इसलिए आप K-combinator का उल्लेख किसी ऐसे व्यक्ति से कर सकते हैं, जो इस शब्दावली से परिचित हो।


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


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


संयुक्त पुस्तकालय


कंबाइनटोरियल लाइब्रेरी ऐसी लाइब्रेरी होती हैं, जो कई कॉम्बीनेटरियल फ़ंक्शंस को एक्सपोर्ट करती हैं जिन्हें साझा करने के लिए डिज़ाइन किया जाता है। इस तरह की लाइब्रेरी का उपयोगकर्ता आसानी से बड़े और अधिक जटिल कार्यों को प्राप्त करने के लिए फ़ंक्शन को एक साथ जोड़ सकता है, जैसे क्यूब्स आसानी से।


एक अच्छी तरह से डिज़ाइन की गई कॉम्बिनर लाइब्रेरी आपको उच्च-स्तरीय कार्यों पर ध्यान केंद्रित करने और निम्न-स्तरीय "शोर" को छिपाने की अनुमति देती है। हमने पहले से ही "क्यों # F का उपयोग करें" श्रृंखला में कई उदाहरणों में उनकी शक्ति को देखा है, और List मॉड्यूल ऐसे कार्यों से भरा है, " fold " और " map " भी दहनशील हैं यदि आप इसके बारे में सोचते हैं।


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


F # में, कॉम्बिनेटर लाइब्रेरीज़ पार्सिंग (FParsec) के लिए उपलब्ध हैं, HTML का निर्माण, टेस्टिंग फ्रेमवर्क, आदि। हम अगली श्रृंखला में बाद में चर्चा करेंगे और कॉम्बिनेटर का उपयोग करेंगे।


पुनरावर्ती कार्य


अक्सर एक फ़ंक्शन को अपने शरीर से खुद को संदर्भित करने की आवश्यकता होती है। एक क्लासिक उदाहरण फाइबोनैचि फ़ंक्शन है।


 let fib i = match i with | 1 -> 1 | 2 -> 1 | n -> fib(n-1) + fib(n-2) 

दुर्भाग्य से, यह फ़ंक्शन संकलित करने में सक्षम नहीं होगा:


 error FS0039: The value or constructor 'fib' is not defined 

आपको संकलक को बताना होगा कि यह एक पुनरावर्ती फ़ंक्शन का उपयोग करता है।


 let rec fib i = match i with | 1 -> 1 | 2 -> 1 | n -> fib(n-1) + fib(n-2) 

पुनरावर्ती कार्य और डेटा संरचनाएं कार्यात्मक प्रोग्रामिंग में बहुत आम हैं, और मुझे बाद में इस विषय के लिए एक पूरी श्रृंखला समर्पित करने की उम्मीद है।


अतिरिक्त संसाधन


F # के लिए कई ट्यूटोरियल हैं, जिनमें उन लोगों के लिए सामग्री शामिल है जो C # या Java अनुभव के साथ आते हैं। निम्नलिखित लिंक उपयोगी हो सकते हैं क्योंकि आप F # में गहराई से जाते हैं:



F # सीखना शुरू करने के कई अन्य तरीके भी वर्णित हैं।


अंत में, एफ # समुदाय बहुत शुरुआती अनुकूल है। स्लैक में एक बहुत सक्रिय चैट है, एफ # सॉफ्टवेयर फाउंडेशन द्वारा समर्थित है, शुरुआती कमरों के साथ जो आप स्वतंत्र रूप से शामिल हो सकते हैं । हम दृढ़ता से अनुशंसा करते हैं कि आप ऐसा करते हैं!


रूसी भाषी समुदाय F # की साइट पर जाना न भूलें! यदि आपके पास भाषा सीखने के बारे में कोई प्रश्न हैं, तो हमें उनसे चैट रूम में चर्चा करने में खुशी होगी:



अनुवाद लेखकों के बारे में


@Kleidemos द्वारा अनुवादित
अनुवाद और संपादकीय परिवर्तन एफ # डेवलपर्स के रूसी भाषी समुदाय के प्रयासों द्वारा किए गए थे। हम इस लेख को प्रकाशन के लिए तैयार करने के लिए @schvepsss और @shwars को भी धन्यवाद देते हैं

Source: https://habr.com/ru/post/hi433398/


All Articles