2016-08-01 8 views
20

मैं सिर्फ पारसेक (हास्केल में थोड़ा अनुभव रखने) से शुरू कर रहा हूं, और मैं मोनैड या आवेदकों का उपयोग करने के बारे में थोड़ा उलझन में हूं। "रियल वर्ल्ड हास्केल", "लिखित यू हास्केल" पढ़ने के बाद मुझे लगता है कि एक समग्र सवाल यह है कि आवेदकों को प्राथमिकता दी जाती है, लेकिन वास्तव में मुझे कोई जानकारी नहीं है।पारसी: आवेदक बनाम मोनाड्स

तो मेरी प्रश्न हैं:

  • क्या दृष्टिकोण पसंद किया जाता है?
  • क्या मोनैड और आवेदक मिश्रित हो सकते हैं (जब वे दूसरे से अधिक उपयोगी होते हैं तो उनका उपयोग करें)
  • यदि अंतिम उत्तर हाँ है, तो क्या मुझे यह करना चाहिए?
+2

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

उत्तर

12

सामान्य रूप से, जो भी आपको सबसे ज्यादा समझ में आता है, उससे शुरू करें। बाद में निम्नलिखित पर विचार करें।

संभव होने पर Applicative (या यहां तक ​​कि Functor) का उपयोग करना अच्छा अभ्यास है। इन उदाहरणों को अनुकूलित करने के लिए जीएचसी जैसे संकलक के लिए सामान्य रूप से आसान है क्योंकि वे Monad से सरल हो सकते हैं। मुझे लगता है कि सामान्य समुदाय सलाह पोस्ट AMP जितनी संभव हो उतनी सामान्य बाधाओं को बनाने के लिए किया गया है। मैं जीएचसी एक्सटेंशन ApplicativeDo के उपयोग की अनुशंसा करता हूं क्योंकि आप do नोटेशन का समान रूप से उपयोग कर सकते हैं जबकि केवल Applicative बाधा प्राप्त करने की आवश्यकता होती है जब यह आवश्यक हो।

चूंकि पार्सर प्रकार Applicative और Monad दोनों का एक उदाहरण है, तो आप दो मिश्रण और मिलान कर सकते हैं। ऐसी स्थितियां हैं जहां यह करना अधिक पठनीय है - यह सब स्थिति पर निर्भर करता है।

इसके अलावा, megaparsec का उपयोग करने पर विचार करें। megaparsecparsec के अधिक हाल ही में फोर्क को अधिक सक्रिय रूप से बनाए रखा गया है।

संपादित

दो चीजें हैं जो, मेरा उत्तर और टिप्पणियों फिर से पढाना, मैं वास्तव में स्पष्ट की एक अच्छा काम नहीं किया:

  • Applicative उपयोग का मुख्य लाभ यह है कि कई प्रकार के लिए यह अधिक कुशल कार्यान्वयन स्वीकार करता है (उदाहरण के लिए (<*>)ap से अधिक प्रदर्शनकारी है)।

  • यदि आप (+) <$> parseNumber <*> parseNumber जैसे कुछ लिखना चाहते हैं, तो ApplicativeDo में ड्रॉप करने की कोई आवश्यकता नहीं है - यह और अधिक वर्बोज़ होगा। मैं केवल ApplicativeDo का उपयोग करता हूं जब आप स्वयं को बहुत लंबे या घोंसला वाले आवेदक अभिव्यक्ति लिखना शुरू करते हैं।

+0

धन्यवाद! मैं मेगापरसेक की जांच करूंगा, अच्छा लगता है (यूनिकोड और इंडेंटेशन समर्थन बहुत अच्छा लग रहा है!) –

+1

यह ज्यादातर * कंपाइलर * अनुकूलन के बारे में नहीं है; यह * पुस्तकालय * अनुकूलन के बारे में बहुत कुछ है। कुछ प्रकार उनके संरचनाओं के आधार पर अतिरिक्त कुशल '<$', 'fmap',' *> ',' <* ', और/या' <*> 'का समर्थन करते हैं; अन्य नहीं करते हैं। प्रत्येक डेटा के लिए 'डेटा.Sequence' को एक प्रमुख गति वृद्धि मिलती है (हालांकि '<*' वर्तमान में गायब है; मुझे इसे ठीक करना होगा)। दूसरी तरफ, सूचियां केवल छोटे हैं (मानचित्र/वाणिज्य के विशेष मामले को छोड़कर)। – dfeuer

+0

@ डीफ्यूर हम्म, यही वह था जिसका अर्थ है "इन उदाहरणों के बाद से वे 'मोनाद' से सरल हो सकते हैं। लेकिन अगर आप टिप्पणी कर रहे हैं, तो मेरा जवाब स्पष्ट नहीं है। :) मैं इस पर अधिक जोर देना नहीं चाहता था क्योंकि जब मैंने 'ParsecT' के लिए' (<*>) 'देखा, तो यह '(>> =)' की तुलना में अतिरिक्त कुशल प्रतीत नहीं होता ... – Alec

63

यह Applicative और Monad के बीच मुख्य अंतर अर्थ पर ध्यान देने लायक हो सकता है, यह निर्धारित करने के लिए जब प्रत्येक उचित है में। प्रकारों की तुलना करें:

(<*>) :: m (s -> t) -> m s -> m t 
(>>=) :: m s -> (s -> m t) -> m t 

<*> लागू करने के लिए, आप दो संगणना, एक समारोह में से एक, एक तर्क के अन्य, तो उनके मूल्यों आवेदन के द्वारा संयोजित किया जाता है चुनें। >>= को तैनात करने के लिए, आप एक गणना चुनते हैं, और आप समझाते हैं कि आप अगले गणना का चयन करने के लिए अपने परिणामी मूल्यों का उपयोग कैसे करेंगे।यह "बैच मोड" और "इंटरैक्टिव" ऑपरेशन के बीच का अंतर है।

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

पार्सिंग से समांतरता तक स्थानांतरण, >>= का उपयोग करने का यह विचार केवल आवश्यक मूल्य-निर्भरता के लिए लोड को फैलाने के अवसरों के बारे में स्पष्टता देता है। जब दो कंप्यूटेशंस <*> के साथ संयुक्त होते हैं, तो न तो दूसरे की प्रतीक्षा करनी पड़ती है। आवेदक-कब-आप-लेकिन-मोनैडिक-जब-आप-गति-गति के लिए सूत्र होना चाहिए। ApplicativeDo का बिंदु कोड के निर्भरता विश्लेषण को स्वचालित करना है जो मोनैडिक शैली में लिखा गया है और इस प्रकार गलती से अपरिवर्तनीय है।

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

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

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

+0

यह भी ध्यान देने योग्य है कि आप '<*>' के साथ किए गए पार्सर्स को '>> =' के साथ बना सकते हैं - हालांकि अतिरिक्त अभिव्यक्ति की हमेशा आवश्यकता नहीं होती है। यह उत्तर अंतरों को आगे बढ़ाता है http://stackoverflow.com/a/7863380/261393 –

+0

क्या आवेदक शैली में प्रोग्रामिंग के लिए आपकी वरीयता है (जिसके द्वारा मेरा मतलब है कि आप "प्रत्यक्ष शैली" के रूप में संदर्भित कर रहे हैं, जैसा कि अलग है "एक 'आवेदक' शैली से") ''=' '' '' से अधिक पसंद करते हैं? –

+1

@ बेंजामिन होडसन: मैंने सोचा था कि चरम पर "सीधी शैली", एक ऐसा होगा जहां आप फ़ंक्शन एप्लिकेशन सिंटैक्स का उपयोग करेंगे (Haskell में '->' फ़ंक्शन स्पेस के लिए आरक्षित)। आधुनिक सेटिंग में एक कार्यान्वयन के उदाहरण के लिए, [इडिस में] (http://docs.idris-lang.org/en/latest/tutorial/interfaces.html?highlight=idiom#idiom-brackets) आप ' [| एफ एक्स वाई + जेड |] '' मतलब + (+) <$> (एफ <$> x <*> y) <*> z' – Cactus

6

@pigworker से आगे (मैं यहां टिप्पणी करने के लिए बहुत नया हूं) join $ fM <*> ... <*> ... <*> ... को पैटर्न के रूप में भी ध्यान देने योग्य है। यह आपको "bind1, bind2, bind3 ..." परिवार बनाता है उसी तरह <$> और <*> आपको एक "fmap1, fmap2, fmap3" मिलता है।

एक शैलीगत बात के रूप में, जब आप do ज्यादा एक ही उपयोग करने के लिए के रूप में आप let का प्रयोग करेंगे combinators यह संभव है करने के लिए पर्याप्त इस्तेमाल कर रहे हैं: एक तरह से उजागर करने के लिए जब आप कुछ नाम करना चाहता था के रूप में। उदाहरण के लिए मैं पार्सर्स में चीजों को अधिक बार नामित करना चाहता हूं, क्योंकि यह शायद कल्पना में नामों के अनुरूप है!

+0

क्या आप इसका विस्तार करने के लिए विस्तार कर सकते हैं? पहला पैराग्राफ अस्पष्ट है; दूसरा कुछ उदाहरणों का उपयोग कर सकता है। – dfeuer

संबंधित मुद्दे