कार्यात्मक प्रोग्रामिंग भाषाएं कैसे काम करती हैं?


92

यदि कार्यात्मक प्रोग्रामिंग भाषाएं किसी भी राज्य को नहीं बचा सकती हैं, तो वे उपयोगकर्ता से इनपुट पढ़ने जैसे सरल सामान कैसे करते हैं? वे इनपुट को कैसे "स्टोर" करते हैं (या उस मामले के लिए कोई डेटा संग्रहीत करते हैं?)

उदाहरण के लिए: यह सरल सी चीज हास्केल जैसी कार्यात्मक प्रोग्रामिंग भाषा में कैसे अनुवाद करेगी?

#include<stdio.h>
int main() {
    int no;
    scanf("%d",&no);
    return 0;
}

(मेरा प्रश्न इस उत्कृष्ट पोस्ट से प्रेरित था: "किंगडम ऑफ नाउन्स में निष्पादन" । इसे पढ़ने से मुझे कुछ बेहतर समझ मिली कि वास्तव में ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग क्या है, कैसे जावा इसे एक चरम तरीके से लागू करता है, और कैसे कार्यात्मक प्रोग्रामिंग भाषाएं ए। इसके विपरीत।)


के संभावित डुप्लिकेट stackoverflow.com/questions/1916692/...
क्रिस कोनवे

4
यह एक अच्छा सवाल है, क्योंकि एक प्रणालीगत स्तर पर एक कंप्यूटर को उपयोगी होने के लिए राज्य की आवश्यकता होती है। मैंने साइमन पेटन-जोन्स (हास्केल के पीछे के देवों में से एक) के साथ एक साक्षात्कार देखा, जहां उन्होंने कहा कि एक कंप्यूटर जो कभी पूरी तरह से स्टेटलेस सॉफ्टवेयर चलाता था, वह केवल एक चीज को पूरा कर सकता था: गर्म हो जाओ! नीचे कई अच्छे जवाब। दो मुख्य रणनीतियाँ हैं: 1) एक अशुद्ध भाषा बनाओ। 2) अमूर्त राज्य के लिए एक चालाक योजना बनाएं, जो हास्केल करता है, अनिवार्य रूप से पुराने को संशोधित करने के बजाय एक नया, थोड़ा परिवर्तित विश्व बना रहा है।
हानि पहुँचाता

14
क्या एसपीजे वहां साइड इफेक्ट की बात नहीं कर रहा था, राज्य की नहीं? शुद्ध संगणना में तर्क बाइंडिंग और कॉल स्टैक में बहुत सारे राज्य निहित हैं, लेकिन साइड इफेक्ट्स के बिना (जैसे, I / O) कुछ भी उपयोगी नहीं कर सकते हैं। दो बिंदु वास्तव में काफी अलग हैं - वहाँ शुद्ध, स्टेटस हास्केल कोड के टन है, और Stateमोनाड बहुत सुरुचिपूर्ण है; दूसरी ओर IOएक बदसूरत, गंदे हैक का उपयोग केवल भद्दे तरीके से किया जाता है।
सीए मैककैन

4
कैमकैन के पास यह अधिकार है। कार्यात्मक भाषाओं में बहुत स्थिति है। यह अनिवार्य रूप से "दूरी पर डरावना कार्रवाई" के बजाय स्पष्ट रूप से प्रबंधित किया जाता है जैसे अनिवार्य भाषाओं में।
JUST MY सही OPINION

1
यहां कुछ भ्रम हो सकता है। शायद कंप्यूटर को उपयोगी होने के लिए प्रभावों की आवश्यकता होती है, लेकिन मुझे लगता है कि यहां सवाल प्रोग्रामिंग भाषाओं के बारे में है, न कि कंप्यूटरों के बारे में।
कोनल

जवाबों:


80

यदि कार्यात्मक प्रोग्रामिंग भाषाएं किसी भी राज्य को नहीं बचा सकती हैं, तो वे कुछ सरल सामान कैसे करते हैं जैसे कि उपयोगकर्ता से इनपुट पढ़ना (मेरा मतलब है कि वे इसे "कैसे स्टोर करें"), या उस मामले के लिए कोई डेटा संग्रहीत कर रहे हैं?

जब आप एकत्रित हुए, कार्यात्मक प्रोग्रामिंग में स्थिति नहीं है - लेकिन इसका मतलब यह नहीं है कि यह डेटा संग्रहीत नहीं कर सकता है। अंतर यह है कि अगर मैं एक (हास्केल) बयान लिखता हूं

let x = func value 3.14 20 "random"
in ...

मुझे इसकी गारंटी है कि मूल्य x हमेशा में समान होता है ...: कुछ भी संभवतः इसे बदल नहीं सकता है। इसी तरह, अगर मेरे पास कोई फ़ंक्शन f :: String -> Integer(स्ट्रिंग लेने और एक पूर्णांक वापस करने वाला एक फ़ंक्शन) है, तो मुझे यकीन है कि fइसके तर्क को संशोधित नहीं करेगा, या किसी भी वैश्विक चर को बदल देगा, या किसी फ़ाइल पर डेटा लिख ​​सकता है, और इसी तरह। जैसा कि ऊपर टिप्पणी में sepp2k ने कहा, यह गैर-परिवर्तनशीलता कार्यक्रमों के बारे में तर्क करने के लिए वास्तव में मददगार है: आप ऐसे कार्य लिखते हैं जो आपके डेटा को मोड़ते हैं, टटोलते हैं, और नई प्रतियां लौटाते हैं, ताकि आप उन्हें एक साथ जोड़ सकें, और आप यह सुनिश्चित कर सकते हैं कि कोई भी नहीं उन फ़ंक्शन कॉल में से कुछ भी "हानिकारक" कर सकते हैं। आप जानते हैं कि xयह हमेशा होता है x, और आपको चिंता करने की ज़रूरत नहीं है कि किसी ने x := foo barघोषणा के बीच में कहीं लिखा हैx और इसका उपयोग, क्योंकि यह असंभव है।

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

main :: IO ()
main = do str <- getLine
          let no = fst . head $ reads str :: Integer
          ...

यह हमें बताता है कि mainएक IO कार्रवाई है जो कुछ भी नहीं लौटाती है; इस क्रिया को निष्पादित करने का अर्थ है हास्केल कार्यक्रम को चलाना। नियम यह है कि IO प्रकार IO क्रिया से बच नहीं सकते हैं; इस संदर्भ में, हम उस क्रिया का उपयोग करते हैं do। इस प्रकार, getLineएक रिटर्न देता है IO String, जिसे दो तरीकों से सोचा जा सकता है: पहला, एक कार्रवाई के रूप में, जो जब चलता है, एक स्ट्रिंग पैदा करता है; दूसरा, एक स्ट्रिंग के रूप में जो आईओ द्वारा "दागी" है क्योंकि यह स्पष्ट रूप से प्राप्त किया गया था। पहला अधिक सही है, लेकिन दूसरा अधिक सहायक हो सकता है। <-लेता हैString से बाहर IO Stringमें और यह भंडार str-लेकिन के बाद से हम एक आईओ कार्रवाई में कर रहे हैं, हम इसे बैक अप लेने रैप करने के लिए, तो यह "भागने" नहीं कर सकते हैं होगा। अगली पंक्ति एक पूर्णांक पढ़ने की कोशिश करती है ( reads) और पहला सफल मैच पकड़ती है (fst . head); यह सब शुद्ध है (कोई IO नहीं), इसलिए हम इसे एक नाम देते हैं let no = ...। हम तो noऔर strमें दोनों का उपयोग कर सकते हैं ...। हम इस प्रकार अशुद्ध डेटा संग्रहीत किया है (से getLineमें str) और शुद्ध डेटा ( let no = ...)।

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

यह आपको हास्केल में IO का उपयोग करने के लिए जानना चाहिए; अगर आप चाहते हैं, तो आप यहाँ रुक सकते हैं। लेकिन अगर आप समझना चाहते हैं कि क्यों काम करता है, तो पढ़ते रहें। (और ध्यान दें कि यह सामान हास्केल के लिए विशिष्ट होगा — अन्य भाषाएँ एक अलग कार्यान्वयन चुन सकती हैं।)

तो यह शायद एक धोखा की तरह लग रहा था, किसी तरह शुद्ध हास्केल में अशुद्धता को जोड़ना। लेकिन ऐसा नहीं है - यह पता चलता है कि हम IO प्रकार को पूरी तरह से शुद्ध हास्केल के भीतर लागू कर सकते हैं (जब तक हम दिए जाते हैं RealWorld)। विचार यह है: एक IO क्रिया IO typeएक फ़ंक्शन के समान है RealWorld -> (type, RealWorld), जो वास्तविक दुनिया को लेता है और दोनों प्रकार की वस्तु typeऔर संशोधित लौटाता है RealWorld। हम तब कुछ कार्यों को परिभाषित करते हैं ताकि हम बिना पागल हुए इस प्रकार का उपयोग कर सकें:

return :: a -> IO a
return a = \rw -> (a,rw)

(>>=) :: IO a -> (a -> IO b) -> IO b
ioa >>= fn = \rw -> let (a,rw') = ioa rw in fn a rw'

पहला हमें IO क्रियाओं के बारे में बात करने की अनुमति देता है जो कुछ भी नहीं करते हैं: return 3एक IO क्रिया है जो वास्तविक दुनिया को क्वेरी नहीं करती है और सिर्फ रिटर्न देती है 3>>=ऑपरेटर, उच्चारण "बाँध", हमें आईओ कार्यों को चलाने के लिए अनुमति देते हैं। यह IO क्रिया से मान निकालता है, फ़ंक्शन के माध्यम से इसे और वास्तविक दुनिया को पास करता है, और परिणामी IO क्रिया देता है। ध्यान दें कि >>=हमारे नियम को लागू करता है कि IO क्रियाओं के परिणामों को कभी भी बचने की अनुमति नहीं है।

फिर हम mainफ़ंक्शन अनुप्रयोगों के निम्नलिखित सामान्य सेट में उपरोक्त को बदल सकते हैं :

main = getLine >>= \str -> let no = (fst . head $ reads str :: Integer) in ...

हस्केल रनटाइम जंप mainप्रारंभिक के साथ शुरू होता है RealWorld, और हम सेट कर रहे हैं! सब कुछ शुद्ध है, यह सिर्फ एक फैंसी वाक्यविन्यास है।

[ संपादित करें: जैसा कि @Conal बताता है , यह वास्तव में वह नहीं है जो हास्केल आईओ करने के लिए उपयोग करता है। यह मॉडल टूटता है यदि आप एक संगोष्ठी जोड़ते हैं, या वास्तव में दुनिया के लिए किसी भी तरह से एक IO कार्रवाई के बीच में बदल जाते हैं, इसलिए हास्केल के लिए इस मॉडल का उपयोग करना असंभव होगा। यह केवल अनुक्रमिक गणना के लिए सटीक है। इस प्रकार, यह हो सकता है कि हास्केल का आईओ थोड़ा चकमा है; यहां तक ​​कि अगर यह नहीं है, यह निश्चित रूप से यह बहुत सुंदर नहीं है। @ कॉनल के अवलोकन के अनुसार, साइमन पेटन-जोन्स ने टैकलिंग द अक्लवर्ड स्क्वाड [pdf] में क्या कहा , धारा 3.1 देखें; वह इन पंक्तियों के साथ एक वैकल्पिक मॉडल को प्रस्तुत कर सकता है, लेकिन फिर इसे अपनी जटिलता के लिए छोड़ देता है और एक अलग तरह का व्यवहार करता है।]

फिर, यह बताता है (बहुत ज्यादा) कैसे IO, और सामान्य रूप से परिवर्तनशीलता, हास्केल में काम करता है; अगर यह सब आप जानना चाहते हैं, तो आप यहां पढ़ना बंद कर सकते हैं। यदि आप सिद्धांत की एक अंतिम खुराक चाहते हैं, तो पढ़ते रहें - लेकिन याद रखें, इस बिंदु पर, हम वास्तव में आपके प्रश्न से बहुत दूर चले गए हैं!

तो एक आखिरी बात: यह इस संरचना को बदल देता है - एक पैरामीट्रिक प्रकार returnऔर >>=- बहुत सामान्य है; यह एक इकाई कहा जाता है, और doसंकेतन, returnऔर >>=उनमें से किसी के साथ काम करते हैं। जैसा कि आपने यहां देखा, सनक जादुई नहीं है; यह सब जादुई है कि doब्लॉक फ़ंक्शन कॉल में बदल जाते हैं। RealWorldप्रकार केवल जगह हम किसी भी जादू देखते हैं। []लिस्ट कंस्ट्रक्टर की तरह टाइप भी मोनड हैं और उनका अशुद्ध कोड से कोई लेना-देना नहीं है।

अब आप जानते हैं कि लगभग एक मठ की अवधारणा के बारे में सब कुछ (कुछ कानूनों को छोड़कर जो संतुष्ट होना चाहिए और औपचारिक गणितीय परिभाषा होनी चाहिए), लेकिन आपके पास अंतर्ज्ञान की कमी है। ऑनलाइन में मोनाड ट्यूटोरियल की एक हास्यास्पद संख्या है; मुझे यह पसंद है , लेकिन आपके पास विकल्प हैं। हालाँकि, यह शायद आपकी मदद नहीं करेगा ; अंतर्ज्ञान प्राप्त करने का एकमात्र वास्तविक तरीका उन्हें उपयोग करने और सही समय पर युगल ट्यूटोरियल पढ़ने के संयोजन के माध्यम से है।

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

(पुनश्च: लंबाई के बारे में क्षमा करें। मैं थोड़ी दूर तक गया था।)


6
वह चीज जो मुझे हमेशा हास्केल के बारे में मिलती है (जो मैंने बनाई है, और सीखने के लिए बहादुर प्रयास कर रहा हूं) वाक्य रचना की कुरूपता है। यह ऐसा है जैसे उन्होंने हर दूसरी भाषा के सबसे बुरे बिट्स ले लिए, उन्हें एक बाल्टी में गिरा दिया और जमकर हंगामा किया। और फिर ये लोग C ++ के भर्ती के बारे में शिकायत करेंगे (स्थानों में) अजीब वाक्य रचना!

19
नील: वाक़ई? मैं वास्तव में हास्केल के वाक्यविन्यास को बहुत साफ पाता हूं। मैं उत्सुक हूँ; क्या आप विशेष रूप से बात कर रहे हैं? (इसके लायक होने के लिए, सी ++ वास्तव में मुझे या तो परेशान नहीं करता है, सिवाय > >टेम्पलेट्स में करने की आवश्यकता के ।)
एंटाल स्पेक्टर-ज़बूसकी

6
मेरी नजर में, जबकि हास्केल का सिंटैक्स उतना साफ नहीं है, कहते हैं, स्कीम, यह घुंघराले ब्रेस भाषाओं के सबसे अच्छे वाक्य विन्यास की तुलना करना शुरू नहीं करता है, यहाँ तक कि C ++ सबसे खराब में से एक है । स्वाद का कोई हिसाब नहीं, मुझे लगता है। मुझे नहीं लगता कि कोई भाषा मौजूद है जो सभी को वाक्यविन्यास से प्रसन्न करती है।
सीए मैककैन

8
@NeilButterworth: मुझे संदेह है कि आपकी समस्या फ़ंक्शन नामों के रूप में बहुत अधिक वाक्यविन्यास नहीं है। यदि फ़ंक्शन >>=या जैसे $अधिक थे, जहां इसके बजाय कहा जाता है bindऔर apply, हैसेल कोड पर्ल की तरह बहुत कम दिखाई देगा। मेरा मतलब हैस्केल और स्कीम सिंटैक्स के बीच मुख्य अंतर यह है कि हैसेल में इन्फिक्स ऑपरेटर्स और वैकल्पिक पार्न्स हैं। अगर लोग infix ऑपरेटर्स के इस्तेमाल से परहेज करेंगे, तो हेकेल कम पार्न वाली स्कीम की तरह दिखेगी।
21

5
@camcann: ठीक है, इंगित करें, लेकिन मेरा क्या मतलब है: योजना का मूल सिंटैक्स है (functionName arg1 arg2)। यदि आप उन पैरेन्स को हटाते हैं functionName arg1 arg2जो हैस्केल सिंटैक्स है। यदि आप मनमाने ढंग से भयानक नामों के साथ infix ऑपरेटरों को अनुमति देते हैं arg1 §$%&/*°^? arg2जो आपको हैसेल की तरह और भी अधिक है। (मैं बस btw चिढ़ा रहा हूँ, मैं वास्तव में हैस्केल की तरह है)।
sepp2k

23

यहाँ बहुत अच्छे उत्तर हैं, लेकिन वे लंबे हैं। मैं एक उपयोगी संक्षिप्त उत्तर देने की कोशिश करने जा रहा हूं:

  • कार्यात्मक भाषाएं उन्हीं स्थानों पर राज्य रखती हैं जो C करता है: नामित चरों में और ढेर पर आवंटित वस्तुओं में। अंतर यह हैं कि:

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

    • "परिवर्तन की स्थिति" मौजूदा चर या वस्तुओं को परिवर्तित करके नहीं बल्कि नए चर को बांधने या नई वस्तुओं को आवंटित करने से नियंत्रित की जाती है।

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

    • कोई भी कार्यक्रम दुनिया की नकल नहीं कर सकता (आप इसे कहां रखेंगे?)

    • कोई भी कार्यक्रम दुनिया को दूर नहीं फेंक सकता है

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

    इस चाल को उनके लैंडमार्क पेपर "इंपीरियल फंक्शनल प्रोग्रामिंग" में साइमन पेटन जोन्स और फिल वाडलर द्वारा खूबसूरती से समझाया गया है ।


4
जहां तक ​​मैं बता सकता हूं, यह IOकहानी ( World -> (a,World)) हास्केल पर लागू होने के दौरान एक मिथक है, क्योंकि यह मॉडल केवल विशुद्ध रूप से अनुक्रमिक गणना बताता है, जबकि हास्केल के IOप्रकार में संगामिति शामिल है। "विशुद्ध रूप से अनुक्रमिक" से मेरा मतलब है कि दुनिया (ब्रह्मांड) को भी गणना के कारण के अलावा, एक अनिवार्य गणना की शुरुआत और अंत के बीच बदलने की अनुमति नहीं है। उदाहरण के लिए, जबकि आपका कंप्यूटर दूर चल रहा है, आपका मस्तिष्क आदि नहीं हो सकता। कंसीडर को कुछ और तरह से हैंडल किया जा सकता है World -> PowerSet [(a,World)], जो नॉनडेटर्मिनिज़्म और इंटरलेविंग के लिए अनुमति देता है।
कॉनल

1
@ जोनल: मुझे लगता है कि आईओ कहानी नोंडेटर्मिनिज़्म और इंटरलेविंग के लिए बहुत अच्छी तरह से सामान्य करती है; अगर मुझे सही याद है, तो "अवाकवर्ड स्क्वाड" पेपर में बहुत अच्छी व्याख्या है। लेकिन मुझे अच्छे पेपर के बारे में पता नहीं है जो स्पष्ट समानता को स्पष्ट रूप से समझाता है।
नॉर्मन रैमसे

3
जैसा कि मैं इसे समझता हूं, "अवाकवर्ड स्क्वाड" कागज़ के सरल संप्रदाय मॉडल को सामान्य करने के प्रयास को छोड़ देता है IO, अर्थात World -> (a,World)(लोकप्रिय और लगातार "मिथक" जिसका मैंने उल्लेख किया है) और इसके बजाय एक परिचालन विवरण देता है। कुछ लोगों को परिचालन शब्दार्थ पसंद है, लेकिन वे मुझे पूरी तरह से असंतुष्ट छोड़ देते हैं। कृपया मेरे उत्तर को दूसरे उत्तर में देखें।
प्रातः 17:10

+1 यह मुझे IO मोनाड्स को समझने में मदद करता है और साथ ही साथ सवाल का जवाब भी देता है।
कैप्टनसी

अधिकांश हास्केल compilers वास्तव में परिभाषित करते हैं IOके रूप में RealWorld -> (a,RealWorld), लेकिन इसके बजाय वास्तव में असली दुनिया का प्रतिनिधित्व यह सिर्फ एक अमूर्त मूल्य के आसपास पारित कर दिया करने के लिए है और समाप्त होता है संकलक द्वारा बाहर अनुकूलित हो रही है कि के।
जेरेमी सूची

19

मैं एक नए उत्तर के लिए एक टिप्पणी उत्तर को तोड़ रहा हूं, अधिक स्थान देने के लिए:

मैंने लिखा:

जहां तक ​​मैं बता सकता हूं, यह IOकहानी ( World -> (a,World)) हास्केल पर लागू होने के दौरान एक मिथक है, क्योंकि यह मॉडल केवल विशुद्ध रूप से अनुक्रमिक गणना बताता है, जबकि हास्केल के IOप्रकार में संगामिति शामिल है। "विशुद्ध रूप से अनुक्रमिक" से मेरा मतलब है कि दुनिया (ब्रह्मांड) को भी गणना के कारण के अलावा, एक अनिवार्य गणना की शुरुआत और अंत के बीच बदलने की अनुमति नहीं है। उदाहरण के लिए, जबकि आपका कंप्यूटर दूर चल रहा है, आपका मस्तिष्क आदि नहीं हो सकता। कंसीडर को कुछ और तरह से हैंडल किया जा सकता है World -> PowerSet [(a,World)], जो नॉनडेटर्मिनिज़्म और इंटरलेविंग के लिए अनुमति देता है।

नॉर्मन ने लिखा:

@ जोनल: मुझे लगता है कि आईओ कहानी नोंडेटर्मिनिज़्म और इंटरलेविंग के लिए बहुत अच्छी तरह से सामान्य करती है; अगर मुझे सही याद है, तो "अवाकवर्ड स्क्वाड" पेपर में बहुत अच्छी व्याख्या है। लेकिन मुझे अच्छे पेपर के बारे में पता नहीं है जो स्पष्ट समानता को स्पष्ट रूप से समझाता है।

@ नोर्मन: किस अर्थ में सामान्य है? मैं सुझाव दे रहा हूं कि आमतौर पर दिए गए डिनोटिस्टिक मॉडल / स्पष्टीकरण World -> (a,World), हास्केल से मेल IOनहीं खाते, क्योंकि यह नॉनडेटर्मिनिज़म और कंसीडर के लिए जिम्मेदार नहीं है। एक और अधिक जटिल मॉडल हो सकता है जो फिट बैठता है, जैसे कि World -> PowerSet [(a,World)], लेकिन मुझे नहीं पता कि क्या इस तरह के मॉडल पर काम किया गया है और पर्याप्त और सुसंगत दिखाया गया है। मुझे व्यक्तिगत रूप से संदेह है कि ऐसा जानवर पाया जा सकता है, जिसे देखते IOहुए हजारों एफएफआई-आयातित अनिवार्य एपीआई कॉल द्वारा आबादी है। और इस तरह, IOअपने उद्देश्य को पूरा कर रहा है:

खुली समस्या: IOमोनद हास्केल के पाप बन गए हैं। (जब भी हमें कुछ समझ में नहीं आता है, हम इसे IO मोनड में टॉस करते हैं।)

(साइमन पीजे की पीओपीएल वार्ता से बाल शर्ट पहने हुए बाल शर्ट पहने हुए: हास्केल पर पूर्वव्यापी ।)

अक्वर्ड स्क्वाड को हटाने की धारा 3.1 में , साइमन बताते हैं कि type IO a = World -> (a, World)"जब हम कंसीडर को जोड़ते हैं तो दृष्टिकोण अच्छा नहीं होता है" सहित। फिर वह एक संभावित वैकल्पिक मॉडल का सुझाव देता है, और फिर यह कहते हुए कि व्याख्यात्मक व्याख्या के प्रयास को छोड़ देता है

हालाँकि, हम इसके बजाय एक ऑपरेशनल शब्दार्थ को अपनाएंगे, जो प्रक्रिया गणना के शब्दार्थों के लिए मानक दृष्टिकोण पर आधारित है।

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


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

1
मुझे यह पसंद है कि World -> PowerSet [World]नॉनडेटर्मिनिज़्म और इंटरलेविंग-स्टाइल कॉन्सिरेन्सी को किस तरह से पकड़ लिया जाता है। यह डोमेन परिभाषा मुझे बताती है कि मुख्यधारा समवर्ती अनिवार्य प्रोग्रामिंग (हास्केल सहित) अट्रैक्टिव है - वस्तुतः क्रमिक रूप से घातीय की तुलना में अधिक जटिल है। हास्केल IOमिथक में मुझे जो बड़ी हानि दिखाई देती है, वह इस अंतर्निहित जटिलता को अस्पष्ट कर रही है, इसके अतिवृष्टि को ध्वस्त कर रही है।
प्रातः

जब मैं देखता हूं कि क्यों World -> (a, World)टूटा हुआ है, तो मुझे यह स्पष्ट नहीं है कि प्रतिस्थापन World -> PowerSet [(a,World)]ठीक से मॉडल निर्णायक क्यों है, आदि मेरे लिए, इसका मतलब यह है कि प्रोग्राम IOको कुछ इस तरह से चलाना चाहिए जैसे कि सूची मोनाड, खुद को सेट के हर आइटम पर लागू करना। IOक्रिया द्वारा । मैं क्या खो रहा हूँ?
एंटाल स्पेक्टर-ज़बूसकी

3
@ एब्सज़: सबसे पहले, मेरा सुझाव दिया मॉडल, World -> PowerSet [(a,World)]सही नहीं है। World -> PowerSet ([World],a)इसके बजाय कोशिश करते हैं। PowerSetसंभावित परिणामों का सेट देता है (nondeterminism)। [World]इंटरमीडिएट स्टेट्स (सूची / नॉनडेर्मिनिज्म मोनाड नहीं) के सीक्वेंस हैं, जो इंटरलेविंग (थ्रेड शेड्यूलिंग) के लिए अनुमति देता है। और ([World],a)यह बिलकुल भी सही नहीं है, क्योंकि यह aसभी मध्यवर्ती राज्यों से गुजरने से पहले एक्सेस की अनुमति देता है। इसके बजाय, परिभाषित करें World -> PowerSet (Computation a)कि कहांdata Computation a = Result a | Step World (Computation a)
कॉनल

मुझे अभी भी कोई समस्या नहीं दिख रही है World -> (a, World)। यदि Worldप्रकार में वास्तव में सभी दुनिया शामिल है, तो इसमें समवर्ती रूप से चलने वाली सभी प्रक्रियाओं की जानकारी भी शामिल है, और सभी गैर-नियतात्मकता के 'यादृच्छिक बीज' भी शामिल हैं। परिणामस्वरूप Worldसमय उन्नत के साथ एक दुनिया है और कुछ बातचीत का प्रदर्शन किया। इस मॉडल के साथ एकमात्र वास्तविक समस्या यह प्रतीत होती है कि यह बहुत सामान्य है और इसके मूल्यों का Worldनिर्माण और हेरफेर नहीं किया जा सकता है।
Rotsor

17

कार्यात्मक प्रोग्रामिंग लैम्ब्डा कैलकुलस से प्राप्त होता है। यदि आप वास्तव में कार्यात्मक प्रोग्रामिंग की जाँच करना चाहते हैं तो http://worrydream.com/AlligatorEggs/ देखें

यह लैम्ब्डा कैलकुलस सीखने और फंक्शनल प्रोग्रामिंग की रोमांचक दुनिया में लाने का एक "मज़ेदार" तरीका है!

लैम्ब्डा कैलकुलस को जानना कार्यात्मक प्रोग्रामिंग में सहायक है।

तो लैंबडा कैलकुलस कई वास्तविक दुनिया की प्रोग्रामिंग भाषाओं जैसे लिस्प, स्कीम, एमएल, हास्केल, ... की नींव है।

मान लीजिए कि हम एक ऐसे फ़ंक्शन का वर्णन करना चाहते हैं जो किसी भी इनपुट में तीन जोड़ता है ऐसा करने के लिए हम लिखेंगे:

plus3 x = succ(succ(succ x)) 

पढ़ें "plus3 एक फ़ंक्शन है, जिसे किसी भी संख्या x पर लागू किया जाता है, x के उत्तराधिकारी के उत्तराधिकारी को जन्म देता है"

ध्यान दें कि किसी भी संख्या में 3 को जोड़ने वाले फ़ंक्शन को प्लस 3 नाम देने की आवश्यकता नहीं है; नाम "plus3" इस फ़ंक्शन के नामकरण के लिए सिर्फ एक सुविधाजनक आशुलिपि है

(plus3 x) (succ 0) ≡ ((λ x. (succ (succ (succ x)))) (succ 0))

सूचना हम एक समारोह के लिए लंबो प्रतीक का उपयोग करते हैं (मुझे लगता है कि यह एक मगरमच्छ की तरह दिखता है, मैं अनुमान लगा रहा हूं कि जहां मगरमच्छ अंडे के लिए विचार आया था)

लैम्ब्डा प्रतीक एलीगेटर (एक फ़ंक्शन) है और एक्स इसका रंग है। आप x को एक तर्क के रूप में भी सोच सकते हैं (लैम्ब्डा कैलकुलस फ़ंक्शन वास्तव में केवल एक तर्क के लिए माना जाता है) बाकी आप इसे फ़ंक्शन के शरीर के रूप में सोच सकते हैं।

अब अमूर्त पर विचार करें:

g  λ f. (f (f (succ 0)))

तर्क f का उपयोग फ़ंक्शन स्थिति (कॉल में) में किया जाता है। हम GA को उच्च-क्रम फ़ंक्शन कहते हैं क्योंकि यह इनपुट के रूप में एक और फ़ंक्शन लेता है। आप अन्य फ़ंक्शन कॉल को " अंडे " के रूप में सोच सकते हैं । अब दो कार्यों या " एलीगेटर्स " को लेते हुए हमने बनाया है कि हम ऐसा कुछ कर सकते हैं:

(g plus3) =  f. (f (f (succ 0)))(λ x . (succ (succ (succ x)))) 
= ((λ x. (succ (succ (succ x)))((λ x. (succ (succ (succ x)))) (succ 0)))
 = ((λ x. (succ (succ (succ x)))) (succ (succ (succ (succ 0)))))
 = (succ (succ (succ (succ (succ (succ (succ 0)))))))

यदि आप ध्यान दें कि आप देख सकते हैं कि हमारा λ f मगरमच्छ हमारे λ x मगरमच्छ को खा जाता है और तब λ x मगरमच्छ मर जाता है। तब हमारे λ x मगरमच्छ को λ एफ के मगरमच्छ के अंडे में पुनर्जन्म होता है। फिर प्रक्रिया दोहराती है और बाईं ओर λ x मगरमच्छ अब दाईं ओर दूसरे λ x मगरमच्छ को खाता है।

फिर आप " Alligators " खाने के नियमों के इस सरल सेट का उपयोग " एलीगेटर्स " को एक व्याकरण डिजाइन करने के लिए कर सकते हैं और इस प्रकार कार्यात्मक प्रोग्रामिंग भाषाओं का जन्म हुआ!

इसलिए आप देख सकते हैं कि क्या आप लैम्ब्डा कैलकुलस को जानते हैं, तो आप समझेंगे कि कार्यात्मक भाषाएँ कैसे काम करती हैं।


@tuckster: मैंने पहले कई बार लैम्ब्डा कैलकुलस का अध्ययन किया है ... और हां AlligatorEggs लेख मेरे लिए मायने रखता है। लेकिन मैं उस प्रोग्रामिंग से संबंधित नहीं कर पा रहा हूं। मेरे लिए, अभी, लेब्रा पथरी एक अलग सिद्धांत की तरह है, बस वहीं है। प्रोग्रामिंग भाषाओं में लैम्ब्डा कैलकुलस की अवधारणाओं का उपयोग कैसे किया जाता है?
लेज़र

3
@eSKay: हास्केल है इसे और अधिक एक सामान्य प्रोग्रामिंग भाषा की तरह लग रहे बनाने के लिए, लैम्ब्डा पथरी वाक्यात्मक चीनी की एक पतली परत के साथ। लिस्प-परिवार की भाषाएं भी अप्रकाशित लैम्ब्डा कैलकुलस से काफी मिलती-जुलती हैं, जो कि एलिगेटर एग्स का प्रतिनिधित्व करता है। लैम्ब्डा कैलकुलस अपने आप में अनिवार्य रूप से एक न्यूनतम प्रोग्रामिंग भाषा है, "कार्यात्मक प्रोग्रामिंग असेंबली भाषा" की तरह।
सीए मैक्कैन

@eSKay: मैंने कुछ उदाहरणों के साथ कैसे संबंधित है, इसके बारे में थोड़ा जोड़ा है। आशा है कि ये आपकी मदद करेगा!
PJT

यदि आप मेरे उत्तर से हटने जा रहे हैं तो क्या आप इस बारे में टिप्पणी छोड़ सकते हैं कि मैं अपने उत्तर को बेहतर बनाने के लिए प्रयास क्यों कर सकता हूं। धन्यवाद।
PJT

14

हास्केल में राज्य को संभालने की तकनीक बहुत सीधी है। और आपको इसे संभालने के लिए भिक्षुओं को समझने की आवश्यकता नहीं है।

राज्य के साथ एक प्रोग्रामिंग भाषा में, आपके पास आमतौर पर कुछ मूल्य संग्रहीत होता है, कुछ कोड निष्पादित होता है, और फिर आपके पास एक नया मूल्य संग्रहीत होता है। अनिवार्य भाषाओं में यह राज्य "पृष्ठभूमि में" कहीं है। एक शुद्ध (शुद्ध) कार्यात्मक भाषा में आप इसे स्पष्ट करते हैं, इसलिए आप राज्य को बदलने वाले फ़ंक्शन को स्पष्ट रूप से लिखते हैं।

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

इसको व्यवस्थित करने में सहायता के लिए मोनाड एक उपकरण है। लेकिन भिक्षु वास्तव में समस्या का हल नहीं हैं। समाधान यह है कि राज्य के बजाय राज्य परिवर्तनों के बारे में सोचना चाहिए।

यह भी I / O के साथ काम करता है। वास्तव में यह क्या होता है: इसके बजाय उपयोगकर्ता से कुछ प्रत्यक्ष समकक्ष के साथ इनपुट प्राप्त scanfकरने और इसे कहीं और संग्रहीत करने के बजाय, आप यह कहने के लिए एक फ़ंक्शन लिखते हैं कि scanfयदि आपके पास यह था, तो आप क्या करेंगे और फिर पास करें I / O API पर कार्य करता है। >>=जब आप IOहास्केल में मोनाड का उपयोग करते हैं तो वास्तव में यही होता है । तो आपको कभी भी किसी I / O के परिणाम को कहीं भी संग्रहीत करने की आवश्यकता नहीं है - आपको बस कोड लिखने की आवश्यकता है जो कहता है कि आप इसे कैसे बदलना चाहते हैं।


8

(कुछ कार्यात्मक भाषाएँ अशुद्ध कार्यों की अनुमति देती हैं।)

के लिए पूरी तरह कार्यात्मक भाषाओं, असली दुनिया बातचीत आम तौर पर समारोह तर्क, इस तरह के रूप में शामिल किया गया है:

RealWorld pureScanf(RealWorld world, const char* format, ...);

अलग-अलग भाषाओं में प्रोग्रामर से दुनिया को अलग करने की अलग-अलग रणनीतियाँ हैं। उदाहरण के लिए हास्केल, worldतर्क छिपाने के लिए साधुओं का उपयोग करता है।


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

int compute_sum_of_squares (int min, int max) {
  int result = 0;
  for (int i = min; i < max; ++ i)
     result += i * i;  // modify "result" in place
  return result;
}

आप एक फ़ंक्शन कॉल में संशोधन भाग को शामिल करते हैं, आमतौर पर लूप को पुनरावृत्ति में बदलते हैं:

int compute_sum_of_squares (int min, int max) {
  if (min >= max)
    return 0;
  else
    return min * min + compute_sum_of_squares(min + 1, max);
}

या बस computeSumOfSquares min max = sum [x*x | x <- [min..max]];-)
fredoverflow

@ श्रेय: सूची बोध केवल एक वाक्यगत चीनी है (और फिर आपको सूची में विस्तार से व्याख्या करने की आवश्यकता है)। और आप कैसे लागू करते हैं sum? अभी भी रिक्रिएशन की जरूरत है।
kennytm

3

कार्यात्मक भाषा राज्य बचा सकती है! वे आमतौर पर या तो आपको प्रोत्साहित करते हैं या ऐसा करने के लिए स्पष्ट होने के लिए प्रोत्साहित करते हैं।

उदाहरण के लिए, हास्केल के स्टेट मोनाड की जाँच करें ।


9
और ध्यान रखें कि राज्य के बारे में कुछ भी नहीं है Stateया Monadयह सक्षम बनाता है, क्योंकि वे दोनों सरल, सामान्य, कार्यात्मक टूल के संदर्भ में परिभाषित किए गए हैं। वे सिर्फ प्रासंगिक पैटर्न कैप्चर करते हैं, इसलिए आपको पहिया को इतना मजबूत करने की आवश्यकता नहीं है।
कॉनल


1

Haskell:

main = do no <- readLn
          print (no + 1)

आप निश्चित रूप से कार्यात्मक भाषाओं में चर के लिए चीजें असाइन कर सकते हैं। आप बस उन्हें बदल नहीं सकते हैं (इसलिए मूल रूप से सभी चर कार्यात्मक भाषाओं में स्थिर हैं)।


@ sepp2k: क्यों, उन्हें बदलने में क्या हर्ज है?
लेज़र

@eSKay यदि आप चर नहीं बदल सकते हैं तो आप जानते हैं कि वे समान हैं। यह डिबग करना आसान बनाता है, आपको सरल कार्य करने के लिए मजबूर करता है जो केवल एक काम करते हैं और बहुत अच्छी तरह से करते हैं। यह भी जब संगामिति के साथ काम करने में बहुत मदद करता है।
हेनरिक हैनसेन

9
@eSKay: कार्यात्मक प्रोग्रामर मानते हैं कि उत्परिवर्तनीय स्थिति बग के लिए कई संभावनाएं पेश करती है और कार्यक्रमों के व्यवहार के बारे में तर्क करना कठिन बना देती है। उदाहरण के लिए यदि आपके पास कोई फ़ंक्शन कॉल है f(x)और आप यह देखना चाहते हैं कि x का मान क्या है, तो आपको बस उस स्थान पर जाना होगा जहां x को परिभाषित किया गया है। यदि x परस्पर थे, तो आपको यह भी विचार करना होगा कि क्या कोई बिंदु है जहाँ x को इसकी परिभाषा और इसके उपयोग के बीच बदला जा सकता है (जो कि गैर-तुच्छ है यदि x स्थानीय चर नहीं है)।
sepp2k

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

5
@eSKay: यह इतना अधिक नहीं है कि उत्परिवर्तन हानिकारक है, यह पता चला है कि यदि आप म्यूटेशन से बचने के लिए सहमत हैं तो यह कोड लिखना बहुत आसान हो जाता है जो कि मॉड्यूलर और पुन: प्रयोज्य है। साझा उत्परिवर्तित स्थिति के बिना, कोड के विभिन्न हिस्सों के बीच युग्मन स्पष्ट हो जाता है और आपके डिजाइन को समझना और बनाए रखना बहुत आसान होता है। जॉन ह्यूजेस मुझसे बेहतर यह बताते हैं; उसके कागज क्यों कार्यात्मक प्रोग्रामिंग मामलों को पकड़ो ।
नॉर्मन रैमसे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.