2012-09-27 19 views
5

मेरे पास तीन कार्य (getRow, getColumn, getBlock) दो तर्क (एक्स और वाई) के साथ हैं जो प्रत्येक एक ही प्रकार की सूची उत्पन्न करते हैं। मैं एक चौथे समारोह है कि उनके outputs concatenates लिखना चाहते हैं:हास्केल में एकाधिक तर्कों पर फ़ंक्शंस की सूची को कैसे मैप करें?

outputList :: Int -> Int -> [Maybe Int] 
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

समारोह काम करता है, लेकिन वहाँ डबल मानचित्र को फिर से लिखने के लिए एक रास्ता एक भी नक्शा (तीन '$' s के साथ) क्या है?

उत्तर

22
import Data.Monoid 

outputList :: Int -> Int -> [Maybe Int] 
outputList = mconcat [getRow, getColumn, getBlock] 

आप एक स्पष्टीकरण चाहिए।

सबसे पहले, मैं स्पष्ट रूप से ध्यान दूंगा कि इन सभी कार्यों का एक ही प्रकार है।

outputList, getRow, getColumn, getBlock :: Int -> Int -> [Maybe Int] 

अब अपनी मूल परिभाषा से शुरू करते हैं।

outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

इन कार्यों एक [Maybe Int] में परिणाम है, और कुछ भी की एक सूची एक monoid है। सूक्ष्म रूप से सूचियों को जोड़ना सूचियों को संयोजित करने जैसा ही है, इसलिए हम को mconcat के साथ प्रतिस्थापित कर सकते हैं।

outputList x y = mconcat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

एक अन्य चीज जो एक मोनॉयड है, एक कार्य है, यदि इसका परिणाम एक मोनॉयड है। यही है, अगर b एक मोनॉयड है, तो a -> b एक मोनॉयड भी है। कार्यों को एकजुट करने के लिए समान पैरामीटर के साथ कार्यों को कॉल करने के समान ही है, फिर परिणामों को एकजुट रूप से संयोजित करना।

तो हम

outputList = mconcat [getRow,getColumn,getBlock] 

हम काम हो गया करने के लिए फिर से

outputList x = mconcat $ map ($ x) [getRow,getColumn,getBlock] 

को सरल बना सकते हैं और फिर!


Typeclassopedia has a section about monoids है, हालांकि इस मामले में मुझे यकीन है कि नहीं कर रहा हूँ यह documentation for Data.Monoid परे है कि इतना कहते हैं।

4

पहले कदम के रूप में हम देख सकते हैं कि अपनी परिभाषा

outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

इस प्रकार समारोह रचना ऑपरेटर (.) बजाय समारोह आवेदन ऑपरेटर की ($) का उपयोग कर फिर से लिखा जा सकता है।

outputList x y = (concat . map ($ y) . map ($ x)) [getRow,getColumn,getBlock] 

अगला हम देखते हैं कि map सूची में fmap का दूसरा नाम है और fmap कानूनों को संतुष्ट करता है, इसलिए, विशेष रूप से, हम map (f . g) == map f . map g है। हम इस कानून को map के एक ही एप्लिकेशन का उपयोग करके एक संस्करण को परिभाषित करने के लिए लागू करते हैं।

outputList x y = (concat . map (($ y) . ($ x))) [getRow,getColumn,getBlock] 

एक अंतिम कदम के रूप में हम concatMap द्वारा concat और map की संरचना बदल सकते हैं।

outputList x y = concatMap (($ y) . ($ x)) [getRow,getColumn,getBlock] 

अंत में, मेरी राय में, हालांकि हास्केल प्रोग्रामर कई फैंसी ऑपरेटरों का उपयोग करते हैं, है ना समारोह को परिभाषित करने के लिए एक शर्म की बात है द्वारा

outputList x y = concatMap (\f -> f x y) [getRow,getColumn,getBlock] 

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

2

मैं @ डेव 4420 के उत्तर के साथ जाऊंगा, क्योंकि यह सबसे संक्षिप्त है और वास्तव में आपका क्या मतलब है व्यक्त करता है।

outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock] 

फ्यूज दो नक्शे:

outputList x y = concat . map (($y) . ($x)) [getRow,getColumn,getBlock] 

बदलें concatMap साथ concat . map:

हालांकि, अगर आप Data.Monoid पर भरोसा नहीं करना चाहता था तो आप के रूप में

मूल कोड इस प्रकार पुनर्लेखन सकता है

outputList x y = concatMap (($y) . ($x)) [getRow,getColumn,getBlock] 

और आप कर चुके हैं।

संपादित करें: aaaaand यह @Jan Christianen के उत्तर जैसा ही है। ओह अच्छा!

+0

वैसे, क्या कोई आंकड़े हैं जब तक हास्केल के बारे में कोई प्रश्न नहीं दिया जाता है? मैं इस धारणा के तहत हूं कि सभी हास्केल सवालों का 9 0 प्रतिशत उत्तर तुरंत उत्तर दिया जाता है। हालांकि यह उत्तर की गुणवत्ता के बारे में कुछ भी नहीं कहता है, मेरी राय में उनके पास काफी उच्च गुणवत्ता है। –

+2

@JanChristiansen: यदि आप चाहें तो स्टैक एक्सचेंज डेटा एक्सप्लोरर का उपयोग करके आप इसका जवाब दे सकते हैं। मैंने बहुत मोटा अनुमान लगाया (स्पष्ट रूप से फ़िल्टर करें, स्वयं जवाबों को अनदेखा करें, और सी।), और सामान्य (यानी, औसत) समय पहले जवाब पोस्ट होने तक लगभग 20 मिनट था। –