2014-10-07 3 views
18

मैं पढ़ रहा हूँ आपको एक हास्केल सीखें और मैंने पहले ही आवेदक को कवर किया है और अब मैं मोनोइड्स पर हूं। मुझे दोनों को समझने में कोई समस्या नहीं है, हालांकि मुझे प्रैक्टिस में आवेदक उपयोगी पाया गया है और मोनॉयड काफी नहीं है। तो मुझे लगता है कि मुझे हास्केल के बारे में कुछ समझ में नहीं आता है।मोनोइड्स का व्यावहारिक उपयोग क्या है?

सबसे पहले, Applicative की बात करते हुए, यह 'कंटेनर' पर विभिन्न कार्यों को करने के लिए एक समान वाक्यविन्यास की तरह बनाता है। इसलिए हम सामान्य कार्यों का उपयोग कर सकते Maybe, सूची पर कार्रवाई करने के लिए, IO (? मैंने कहा जाना चाहिए था monads मैं monads अभी तक पता नहीं), कार्य:

λ> :m + Control.Applicative 
λ> (+) <$> (Just 10) <*> (Just 13) 
Just 23 
λ> (+) <$> [1..5] <*> [1..5] 
[2,3,4,5,6,3,4,5,6,7,4,5,6,7,8,5,6,7,8,9,6,7,8,9,10] 
λ> (++) <$> getLine <*> getLine 
one line 
and another one 
"one line and another one" 
λ> (+) <$> (* 7) <*> (+ 7) $ 10 
87 

तो अनुप्रयोगी एक अमूर्त है। मुझे लगता है कि हम इसके बिना जी सकते हैं लेकिन यह कुछ विचार मोड स्पष्ट रूप से व्यक्त करने में मदद करता है और यह ठीक है।

अब, Monoid पर एक नज़र डालें। यह भी अमूर्त और बहुत सरल है। लेकिन क्या यह हमारी मदद करता है? किताब से हर उदाहरण के लिए यह वहाँ काम करने के लिए और अधिक स्पष्ट तरीका है कि स्पष्ट हो रहा है:

λ> :m + Data.Monoid 
λ> mempty :: [a] 
[] 
λ> [1..3] `mappend` [4..6] 
[1,2,3,4,5,6] 
λ> [1..3] ++ [4..6] 
[1,2,3,4,5,6] 
λ> mconcat [[1,2],[3,6],[9]] 
[1,2,3,6,9] 
λ> concat [[1,2],[3,6],[9]] 
[1,2,3,6,9] 
λ> getProduct $ Product 3 `mappend` Product 9 
27 
λ> 3 * 9 
27 
λ> getProduct $ Product 3 `mappend` Product 4 `mappend` Product 2 
24 
λ> product [3,4,2] 
24 
λ> getSum . mconcat . map Sum $ [1,2,3] 
6 
λ> sum [1..3] 
6 
λ> getAny . mconcat . map Any $ [False, False, False, True] 
True 
λ> or [False, False, False, True] 
True 
λ> getAll . mconcat . map All $ [True, True, True] 
True 
λ> and [True, True, True] 
True 

तो हम कुछ पैटर्न देखा और नए प्रकार वर्ग बनाया है ... ठीक है, मैं गणित की तरह। लेकिन व्यावहारिक दृष्टिकोण से, Monoid का क्या मतलब है? यह विचारों को बेहतर व्यक्त करने में हमारी सहायता कैसे करता है?

+2

यदि आप कुछ उन्नत सामग्री में खोदना चाहते हैं जो वास्तव में मोनोइड्स की शक्ति दिखाता है, तो [उंगली के पेड़] देखें (http://www.cs.ox.ac.uk/ralf.hinze/publications/FingerTrees.pdf) ('डेटा.Sequence' के पीछे इंजन)। मुझे यकीन है कि सरल उदाहरण हैं जिन्हें मैं अभी नहीं सोच सकता। – luqui

+4

मैं आपको इस उत्कृष्ट [दान पाइपोनी] (http://blog.sigfpe.com/2009/01/haskell-monoids-and-their-uses.html) लेख के माध्यम से जाने का सुझाव दूंगा। – Sibi

+0

संबंधित, लेकिन डुप्लिकेट प्रश्न नहीं: [Data.Monoid में उन सभी नए प्रकार के रैपर का व्यावहारिक मूल्य क्या है) (http://stackoverflow.com/questions/22080564/whats-the-practical-value-of-all-those- न्यूटाइप-रैपर-इन-डेटा-मोनॉयड) – AndrewC

उत्तर

25

गेब्रियल गोंजालेज़ ने अपने ब्लॉग में बड़ी जानकारी दी कि आपको देखभाल क्यों करनी चाहिए, और आपको वास्तव में परवाह करना चाहिए। आप इसे here पढ़ सकते हैं (और this भी देखें)।

यह स्केलेबिलिटी, आर्किटेक्चर & एपीआई डिज़ाइन के बारे में है।

एक साथ एक कई घटक कम्बाइन ग्रुप ए के एक "नेटवर्क" या ग्रुप बी के "टोपोलॉजी"

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

तो आप अपने डिजाइन या डोमेन को बेहतर बनाने के लिए मॉड्यूल ए को बदलना चाहते हैं, तो आप करते हैं। ओह, लेकिन अब मॉड्यूल बी & सी जो टूटने पर निर्भर करता है। आप बी ठीक है, महान। अब आप सी को ठीक करते हैं। अब बी टूट गया, क्योंकि बी ने कुछ सी की कार्यक्षमता भी उपयोग की। और मैं इसके साथ हमेशा के लिए जा सकता हूं, और यदि आपने कभी ओओपी का उपयोग किया - तो आप भी कर सकते हैं।

तो फिर वहाँ क्या गेब्रियल "हास्केल वास्तुकला" कहता है: अपने substituent भागों से

कई घटक कम्बाइन ग्रुप ए के एक साथ एक ही प्रकार एक का एक नया घटक उत्पन्न करने के लिए, चरित्र में पृथक

यह इस मुद्दे को सुन्दरता से हल करता है। असल में: अपने मॉड्यूल को परत न करें या विशेष बनाने के लिए विस्तार न करें।
इसके बजाय, गठबंधन करें।

तो अब, प्रोत्साहित किया जाता है कि "मेरे पास एकाधिक एक्स है, इसलिए चलिए एक प्रकार का निर्माण करने के लिए एक प्रकार बनाते हैं", आप कहते हैं, "मेरे पास एकाधिक एक्स है, इसलिए चलिए उन्हें एक्स में जोड़ दें"। या सरल अंग्रेजी में: "चलो पहले प्रकार में संगत प्रकार बनाते हैं।" (क्या आप मोनोइड्स को अभी तक गुप्त महसूस करते हैं?)।

कल्पना कीजिए कि आप अपने वेबपृष्ठ या एप्लिकेशन के लिए एक फॉर्म बनाना चाहते हैं, और आपके पास मॉड्यूल "व्यक्तिगत सूचना फॉर्म" है जिसे आपने बनाया है क्योंकि आपको व्यक्तिगत जानकारी की आवश्यकता है। बाद में आपको पता चला कि आपको "चेंज पिक्चर फॉर्म" की भी आवश्यकता है, इसलिए इसे तुरंत लिखा। और अब आप कहते हैं कि मैं उन्हें गठबंधन करना चाहता हूं, तो चलिए एक "व्यक्तिगत जानकारी & पिक्चर फॉर्म" मॉड्यूल बनाते हैं। और वास्तविक जीवन में स्केलेबल अनुप्रयोगों में यह हाथ से बाहर निकल सकता है। शायद नहीं रूपों लेकिन प्रदर्शित करने के लिए के साथ, आप लिखें और रचना करने की जरूरत है ताकि आप के साथ "व्यक्तिगत जानकारी & चित्र परिवर्तित & पासवर्ड बदलें & स्थिति बदलें & प्रबंधित खत्म हो जाएगा दोस्त & प्रबंधित इच्छा-सूची सेटिंग्स & देखें बदलें & कृपया मुझे अब और विस्तार नहीं & कृपया & कृपया रुको! & बंद करो !!!! " मॉड्यूल। यह सुंदर नहीं है, और आपको एपीआई में इस जटिलता को प्रबंधित करना होगा। ओह, और यदि आप कुछ भी बदलना चाहते हैं - तो शायद इसकी निर्भरताएं हो सकती हैं। तो .. हाँ .. नरक में आपका स्वागत है। इसलिए हम उन्हें कोई आवश्यकता नहीं क्योंकि वे हमेशा combinability की रक्षा

ये कपोल-कल्पना पैमाने limitlessly,:

अब दूसरा विकल्प को देखो, लेकिन पहले के लाभ को देखो, क्योंकि यह यह करने के लिए हमें मार्गदर्शन करेंगे चलो शीर्ष पर आगे abrasctions परत करने के लिए। यह एक कारण है कि आपको हास्केल क्यों सीखना चाहिए: फ्लैट आर्किटेक्चर बनाने के लिए आप सीखते हैं।

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

और इसलिए, आपको दो रूपों को लेने और एक रूप प्राप्त करने की कुंजी के कारण अब एक गन्दा जटिल पेड़ नहीं मिलता है। तो Form -> Form -> Form। और जैसा कि आप पहले से ही स्पष्ट रूप से देख सकते हैं, यह हस्ताक्षर mappend का एक उदाहरण है।

विकल्प, और पारंपरिक वास्तुकला शायद a -> b -> c और फिर c -> d -> e और उसके बाद कैसा दिखेगा ...

अब, रूपों के साथ यह इतना चुनौतीपूर्ण नहीं है; वास्तविक दुनिया अनुप्रयोगों में इस के साथ काम करना चुनौती है। और ऐसा करने के लिए बस आप जितना कर सकते हैं उतना पूछें (क्योंकि यह देखता है, जैसा कि आप देख सकते हैं): मैं इस अवधारणा को कैसे बना सकता हूं? और चूंकि मोनोइड्स इसे प्राप्त करने के लिए एक आसान तरीका है (हम सरल चाहते हैं) खुद से पहले पूछें: यह अवधारणा एक मोनॉयड कैसी है?

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

+2

+1 ग्रेट आलेख और उत्तर! – Mark

+1

आप [इस पोस्ट] का उल्लेख भी करना चाहेंगे (http://www.haskellforall.com/2014/07/equational-reasoning-at-scale.html) जो विशेष रूप से चल रहे उदाहरण के रूप में 'मोनॉयड' का उपयोग करता है। –

6

यह बात यह है कि जब आप Int को Product के रूप में टैग करते हैं, तो आप पूर्णांक को गुणा करने के लिए अपना इरादा व्यक्त करते हैं। और उन्हें Sum के रूप में टैग करके, एक साथ जोड़ा जा सकता है।

फिर आप दोनों पर mconcat का उपयोग कर सकते हैं। इसका उपयोग किया जाता है उदा। Foldable में जहां एक foldMap एक विशिष्ट मोनोइड के तरीके में तत्वों को संयोजित करते समय, एक युक्त संरचना पर तह करने का विचार व्यक्त करता है।

9

ठीक है, मुझे गणित पसंद है। लेकिन व्यावहारिक दृष्टिकोण से, मोनॉयड का क्या मतलब है? यह विचारों को बेहतर व्यक्त करने में हमारी सहायता कैसे करता है?

यह एक एपीआई है। एक साधारण एक। का समर्थन करने वाले प्रकारों के लिए:

  • एक शून्य तत्व
  • होने एक संलग्न आपरेशन होने

प्रकार के बहुत सारे इन आपरेशनों समर्थन करते हैं। इसलिए संचालन और एक एपीआई के लिए नाम रखने से हमें इस तथ्य को और अधिक स्पष्ट रूप से कैप्चर करने में मदद मिलती है।

एपीआई अच्छे हैं क्योंकि वे हमें कोड का पुन: उपयोग करने और अवधारणाओं का पुन: उपयोग करने देते हैं। मतलब बेहतर, अधिक रखरखाव कोड।

5

एक बहुत ही सरल उदाहरण foldMap है। बस इस एक समारोह में विभिन्न monoids प्लग इन करके, आप की गणना कर सकते हैं:

  • first और last तत्व,
  • sum या तत्वों की product (यह भी उनकी औसत आदि से),
  • जांच अगर all तत्वों या any किसी दिए गए संपत्ति है,
  • अधिक से अधिक या कम से कम तत्व की गणना,
  • एक संग्रह करने के लिए तत्वों के नक्शे (सूचियों की तरह, sets, तार, Text, ByteString या बाइटस्ट्रिंग Builder) और उन्हें एक साथ संयोजित करें - वे सभी मोनोइड्स हैं।

इसके अलावा, monoids composable हैं: अगर a और b monoids हैं, इसलिए (a, b) है। तो आप आसानी से एक पास में कई अलग-अलग monoidal मानों की गणना कर सकते हैं (तत्वों के औसत की गणना करते समय योग और उत्पाद की तरह)।

और हालांकि आप monoids, foldr या foldl का उपयोग किए बिना यह सब कर सकते हैं, यह बहुत अधिक बोझिल और भी अक्सर कम प्रभावी है: उदाहरण के लिए, आप एक संतुलित द्विआधारी पेड़ है और आप अपने न्यूनतम और अधिकतम तत्व को खोजने के लिए चाहते हैं, आप foldr (या foldl साथ दोनों) के साथ प्रभावी रूप से दोनों नहीं कर सकते, एक हमेशा हे (एन) मामलों में से एक के लिए होगा, जबकि जब उचित monoids साथ foldMap का उपयोग कर, यह हे (लॉग एन) हो जाएगा दोनों मामलों में

और यह सब सिर्फ एक ही समारोह foldMap था!कई अन्य दिलचस्प अनुप्रयोग हैं। एक देने के लिए, exponentiation by squaring शक्तियों की गणना करने का एक प्रभावी तरीका है। लेकिन यह वास्तव में कंप्यूटिंग शक्तियों से बंधे नहीं है। आप इसे किसी भी monoid के लिए कार्यान्वित कर सकते हैं, और यदि <>ओ (1) है, तो आपके पास n-समय x <> ... <> x कंप्यूटिंग का एक प्रभावी तरीका है। और अचानक आप कुशल मैट्रिक्स एक्सपोनिएशन कर सकते हैं और n -th Fibonacci number पर केवल ओ (लॉग एन) गुणा के साथ गणना कर सकते हैं। सेमिग्रुप में देखें times1p

Monoids and Finger Trees भी देखें।

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