जटिल भाग लूप है। हमें इसके साथ शुरू करते हैं। एक लूप को आमतौर पर एकल फ़ंक्शन के साथ पुनरावृत्ति व्यक्त करके कार्यात्मक शैली में बदल दिया जाता है। एक पुनरावृति लूप वेरिएबल का रूपांतरण है।
यहाँ एक सामान्य लूप का कार्यात्मक कार्यान्वयन है:
loop : v -> (v -> v) -> (v -> Bool) -> v
loop init iter cond_to_cont =
if cond_to_cont init
then loop (iter init) iter cond
else init
यह लूप वेरिएबल का एक प्रारंभिक मूल्य लेता है, जो फ़ंक्शन एक एकल पुनरावृत्ति [लूप वेरिएबल पर]] (लूप को जारी रखने के लिए एक शर्त) को व्यक्त करता है।
आपका उदाहरण एक सरणी पर एक लूप का उपयोग करता है, जो भी टूट जाता है। अपनी अनिवार्य भाषा में इस क्षमता को भाषा में ही पकाया जाता है। कार्यात्मक प्रोग्रामिंग में ऐसी क्षमता आमतौर पर पुस्तकालय स्तर पर लागू की जाती है। यहाँ एक संभावित कार्यान्वयन है
module Array (foldlc) where
foldlc : v -> (v -> e -> v) -> (v -> Bool) -> Array e -> v
foldlc init iter cond_to_cont arr =
loop
(init, 0)
(λ (val, next_pos) -> (iter val (at next_pos arr), next_pos + 1))
(λ (val, next_pos) -> and (cond_to_cont val) (next_pos < size arr))
में इस :
मैं एक (वैल, अगली_पोजिशन) जोड़ी का उपयोग करता हूं जिसमें लूप वैरिएबल बाहर दिखाई देता है और एरे में स्थिति, जिसे यह फ़ंक्शन छुपाता है।
सामान्य लूप की तुलना में पुनरावृत्ति फ़ंक्शन थोड़ा अधिक जटिल है, यह संस्करण सरणी के वर्तमान तत्व का उपयोग करना संभव बनाता है। [यह करी रूप में है।]
ऐसे कार्यों को आमतौर पर "गुना" नाम दिया गया है।
मैंने यह इंगित करने के लिए नाम में "एल" डाला कि सरणी के तत्वों का संचय बाएं-साहचर्य तरीके से किया जाता है; कम से उच्च सूचकांक के लिए एक सरणी पुनरावृति करने के लिए अनिवार्य प्रोग्रामिंग भाषाओं की आदत की नकल करना।
मैंने यह संकेत करने के लिए नाम में "c" डाला कि गुना का यह संस्करण एक ऐसी स्थिति लेता है जो नियंत्रण करता है कि क्या और कब लूप को जल्दी रोका जाए।
बेशक इस तरह के उपयोगिता कार्यों को बेस लाइब्रेरी में आसानी से उपलब्ध कार्यात्मक प्रोग्रामिंग भाषा के साथ उपलब्ध होने की संभावना है। मैंने उन्हें यहाँ प्रदर्शन के लिए लिखा था।
अब जब हमारे पास सभी उपकरण हैं जो अनिवार्य मामले में भाषा में हैं, तो हम आपके उदाहरण की विशिष्ट कार्यक्षमता को लागू करने के लिए बदल सकते हैं।
आपके लूप में चर एक जोड़ी है ('उत्तर', एक बूलियन जो कि जारी रखने के लिए एन्कोड करता है)।
iter : (Int, Bool) -> Int -> (Int, Bool)
iter (answer, cont) collection_element =
let new_answer = answer + collection_element
in case new_answer of
10 -> (new_answer, false)
150 -> (new_answer + 100, true)
_ -> (new_answer, true)
ध्यान दें कि मैंने एक नया "वैरिएबल" 'new_answer' प्रयोग किया है। ऐसा इसलिए है क्योंकि कार्यात्मक प्रोग्रामिंग में मैं पहले से ही आरंभिक "चर" के मूल्य को नहीं बदल सकता। मुझे प्रदर्शन की चिंता नहीं है, कंपाइलर को जीवन-काल विश्लेषण के माध्यम से 'new_answer' के लिए 'जवाब' की स्मृति का पुन: उपयोग करने के लिए मिल सकता है, अगर यह सोचता है कि यह अधिक कुशल है।
पहले विकसित हमारे लूप फ़ंक्शन में इसे शामिल करना:
doSomeCalc :: Array Int -> Int
doSomeCalc arr = fst (Array.foldlc (0, true) iter snd arr)
"एरे" यहाँ मॉड्यूल नाम है जो फ़ंक्शन फोल्डक निर्यात करता है।
"मुट्ठी", "दूसरा" उन कार्यों के लिए खड़ा है जो अपने जोड़ी पैरामीटर के पहले, दूसरे घटक को वापस करते हैं
fst : (x, y) -> x
snd : (x, y) -> y
इस मामले में "बिंदु मुक्त" शैली doSomeCalc के कार्यान्वयन की पठनीयता बढ़ाती है:
doSomeCalc = Array.foldlc (0, true) iter snd >>> fst
(>>>) फ़ंक्शन रचना है: (>>>) : (a -> b) -> (b -> c) -> (a -> c)
यह ऊपर के समान है, बस "अरेस्ट" पैरामीटर को परिभाषित समीकरण के दोनों किनारों से छोड़ दिया जाता है।
एक अंतिम बात: मामले की जाँच (सरणी == अशक्त)। बेहतर डिज़ाइन की गई प्रोग्रामिंग भाषाओं में, लेकिन यहां तक कि कुछ बुनियादी अनुशासन वाली बुरी तरह से डिज़ाइन की गई भाषाओं में, बल्कि गैर-अस्तित्व को व्यक्त करने के लिए एक वैकल्पिक प्रकार का उपयोग करता है। कार्यात्मक प्रोग्रामिंग के साथ ऐसा करने के लिए बहुत कुछ नहीं है, जो सवाल अंततः के बारे में है, इस प्रकार मैं इसके साथ सौदा नहीं करता हूं।
break
और लूप के अंदर सेreturn answer
बदला जा सकता हैreturn
। एफपी में आप निरंतरता का उपयोग करके इस शुरुआती रिटर्न को लागू कर सकते हैं, उदाहरण के लिए देखें en.wikipedia.org/wiki/Continuation