2012-09-28 15 views
6

खोजने के लिए पैटर्न का उपयोग करना मैं के माध्यम से काम कर रहा हूं Haskell की मूल बातें के साथ गति के लिए आने के लिए आपको एक हास्केल सीखें। मैं दोनों कार्यात्मक प्रोग्रामिंग और पैटर्न मिलान के साथ बहुत सहज हूं, लेकिन बाद में गणित यह करता है।एनएच तत्व

अध्याय 4.1 में head की भोली कार्यान्वयन के रूप में ही भावना में, मैं last के रूप में की एक सीधी सादी कार्यान्वयन के साथ रवाना हुए:

last1 :: [a] -> a 
last1 (_:x:[]) = x 

हालांकि, बुला last1 [1,2,3,4] एक त्रुटि Exception: ... Non-exhaustive patterns in function last1 दे दी है। मैं समझता हूं कि यह त्रुटि दर्शाती है कि निर्दिष्ट पैटर्न में सभी संभावित इनपुट शामिल नहीं होते हैं और आमतौर पर, एक पकड़-सभी पैटर्न आवश्यक है (जो मैंने प्रदान नहीं किया है)। हालांकि, मुझे बिल्कुल यकीन नहीं है कि मुझे अपने इनपुट के लिए यह त्रुटि क्यों मिलती है।

प्रश्न 1: (मेरी गलत दृष्टिकोण का) मेरी समझ है कि पहला तत्व _ द्वारा कब्जा कर लिया है और बाकी x को असाइन किए जाएंगे, जो नहीं है मैं वास्तव में क्या चाहते थे, है। हालांकि, यह एक प्रकार की त्रुटि नहीं देनी चाहिए, क्योंकि मैंने [a] -> a निर्दिष्ट किया है, लेकिन x अब एक सूची है?

ध्यान दें कि यह कैसे एक काम last समारोह लिखने के बारे में नहीं है - मैं जानता हूँ कि मैं के रूप में (अन्य संभावनाओं के बीच)

last2 :: [a] -> a 
last2 [x] = x 
last2 (_:x) = last2 x 

प्रश्न 2 यह लिख सकते हैं: बेहतर का एक ही विषय के साथ हास्केल में मिलान पैटर्न को समझना, मैं पिछले तत्व को चुनने के लिए पैटर्न मिलान का उपयोग कैसे कर सकता हूं या अधिक सामान्य रूप से n किसी दिए गए सूची से वें तत्व, [1..10] कह सकता हूं?

This answer पता चलता है कि आप ViewPatterns विस्तार के साथ मिलान पद्धति का उपयोग कर पिछले तत्व बाध्य कर सकते हैं, लेकिन यह अजीब लगता है के लिए head

की तरह एक अनुरूप "सरल" पैटर्न में मेथेमेटिका, मैं होता नहीं है कि शायद इसे लिखने के रूप में:

Range[10] /. {Repeated[_, {5}], x_, ___} :> x 
(* 6 *) 

6 तत्व और

Range[10] /. {___, x_} :> x 
(* 10 *) 
बाहर लेने के लिए एक गैर-खाली सूची के अंतिम तत्व को चुनने के लिए

मैं क्षमा चाहता हूं कि यह बाद में पाठ में शामिल है, लेकिन मैं प्रत्येक विषय और अवधारणा से संबंधित होने की कोशिश कर रहा हूं क्योंकि मैं उन सभी भाषाओं में कैसे संभाला जाता हूं, जिन्हें मैं जानता हूं ताकि मैं मतभेदों की सराहना कर सकूं और समानताएं।

उत्तर

8

अपने पहले प्रयास के परिणाम को समझने के लिए, आपको यह देखने की आवश्यकता है कि सूची डेटा कैसे परिभाषित किया गया है। सूचियां कुछ हद तक विशेष वाक्यविन्यास का आनंद लेती हैं, लेकिन आप इसे इस तरह लिखेंगे।

data List a = (:) a (List a) 
      | [] 

तो, अपनी सूची [1 .. 10] वास्तव में के रूप में

(1 : (2 : (3 : (4 : [])))) 

इसके अलावा, अपने पैटर्न last1 के लिए संरचित है (:) ऑपरेटर के अधिकार संबद्धता के कारण वास्तव में लग रहा है

last1 :: [a] -> a 
last1 (_:(x:[])) = x 

यही कारण है कि 'x' आपकी सूची के तत्व के समान प्रकार है; यह पहला तर्क है (:) कन्स्ट्रक्टर।

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

यदि आप चाहते थे, तो आप अधिक पैटर्न जोड़ सकते हैं, लेकिन यह साबित नहीं होगा कि सहायक। आप के रूप में

last2 :: [a] -> a 
last2 (x:[])  = x 
last2 (_:x:[]) = x 
last2 (_:_:x:[]) = x 
     ... 
last2 (x:xs) = last2 xs 

यह लिख सकता है लेकिन मामलों की एक अनंत संख्या के बिना, आप इनपुट सभी सूचियों को लंबाई के लिए समारोह को पूरा नहीं कर सकता। जब आप इस तथ्य पर विचार करते हैं कि सूचियां असीमित रूप से लंबे समय तक हो सकती हैं तो यह और भी संदिग्ध है; आप उससे मेल खाने के लिए किस पैटर्न का उपयोग करेंगे?

+0

स्पष्टीकरण के लिए धन्यवाद! इससे यह स्पष्ट हो जाता है कि यह क्यों काम नहीं कर रहा था। क्या एकाधिक तत्वों से मेल खाने के लिए कोई पैटर्न है? उदाहरण के लिए, मेरे गणित उदाहरण (अंत में) में '{___, x_}' पंक्ति में, '___' का अर्थ है "शून्य या अधिक" और '_' का अर्थ है" बिल्कुल एक "। इससे मुझे अंतिम तत्व को छोड़कर सबकुछ त्यागने की अनुमति मिलती है, क्योंकि अब मैंने सूची की संरचना का स्पष्ट रूप से वर्णन किया है। मैं समझता हूं कि यह शायद वाक्य रचनात्मक चीनी है और वास्तविक रिकर्सन/बैकट्रैकिंग हुड के नीचे छिपी हुई है। – abcd

+0

@yoda Haskell के पैटर्न मिलान के साथ ऐसा करने का कोई तरीका नहीं है (जिसे मैं कम से कम जानता हूं)। यह एक गणित विशिष्ट विशेषता की तरह लगता है। आम तौर पर, हास्केल का डिज़ाइन आम तौर पर "विशेष" डेटा प्रकारों से बचाता है जो बहुत सी अतिरिक्त घंटियाँ और सीटी (सूचियों और टुपल्स के लिए कुछ अच्छे वाक्यविन्यास को छोड़कर) प्राप्त करते हैं। हास्केल भाषा में अतिरिक्त सामान जोड़ने पर कार्यों को पसंद करता है। – sabauma

+0

धन्यवाद, यही मैंने सोचा था। मैं इस दर्शन की सराहना भी कर सकता हूं ... मुझे थोड़ा और सोचने के लिए मजबूर करता है। कम से कम, मुझे इसके साथ कार्यात्मक प्रोग्रामिंग सीखने की चिंता करने की ज़रूरत नहीं है! :) – abcd

2

पैटर्न पैटर्न का उपयोग किए बिना पैटर्न मिलान को "अंतिम" तत्व प्राप्त करने का कोई तरीका नहीं है। इसका कारण यह है कि रिकर्सन (कम से कम स्पष्ट रूप से) का उपयोग किए बिना किसी सूची का अंतिम तत्व प्राप्त करने का कोई तरीका नहीं है, और और भी, अंतिम तत्व प्राप्त करने के लिए decidable तरीका नहीं है।

आपका कोड

last1 (_:x:[]) = x 

तरह

last1 (_:(x:[])) = x 

जो

last1 a = case a of 
       (_:b) -> case b of 
          (x:c) -> case c of 
              [] -> x 

में डी-sugared किया जा सकता पार्स किया जाना चाहिए इस अभ्यास हम देखें कि आपके कोड करता है पूरा होने: आप एक पैटर्न लिखा है जो एक सूची से मेल खाएगा यदि सूची के बाहरीतम कन्स्ट्रक्टर एक विपक्ष सेल ए है अगला कन्स्ट्रक्टर एनडी एक विपक्ष है और तीसरा कन्स्ट्रक्टर एक शून्य है।

तो

last1 [1,2,3,4] 

के मामले में हम

last1 [1,2,3,4] 
= last1 (1:(2:(3:(4:[])))) 
= case (1:(2:(3:(4:[])))) of 
     (_:b) -> case b of 
        (x:c) -> case c of 
            [] -> x 
= case (2:(3:(4:[]))) of 
     (x:c) -> case c of 
        [] -> x 
= let x = 2 in case (3:(4:[])) of 
        [] -> x 
= pattern match failure 
+0

इससे यह बहुत स्पष्ट हो जाता है, धन्यवाद! मुझे लगता है कि मैं गणित के '{___, x_}' जैसे पैटर्न की तलाश में था, जहां '___' का मतलब है "शून्य या अधिक" और '_' का अर्थ बिल्कुल एक है, लेकिन आप सही हैं, यह केवल वाक्य रचनात्मक चीनी है जो कुछ छुपाती है हुड के नीचे पुनरावृत्ति/बैकट्रैकिंग की तरह। स्पष्टीकरण के लिए – abcd

2

आपका उदाहरण है

last1 (_:x:[]) = x 

केवल दो तत्वों प्रपत्र a:b:[] अर्थात् सूचियों वाले सूचियों से मेल खाता है। _ बाध्यकारी के बिना सूची के प्रमुख से मेल खाता है, x निम्न तत्व से मेल खाता है, और खाली सूची स्वयं मेल खाती है।

जब पैटर्न मिलान सूचियां, केवल सही-वस्तु आइटम सूची का प्रतिनिधित्व करता है - मिलान की गई सूची की पूंछ।

आप की तरह एक समारोह के साथ एक सूची से n वें तत्व प्राप्त कर सकते हैं:

getNth :: [a] -> Int -> a 
getNth [] _ = error "Out of range" 
getNth (h:t) 0 = h 
getNth (h:t) n = getNth t (n-1) 

यह निर्मित !! ऑपरेटर जैसे का उपयोग कर [1..10] !! 5

+0

धन्यवाद। हां, मुझे '!!' ऑपरेटर के बारे में पता है, लेकिन मुझे पूरी तरह से पैटर्न मिलान करके, मेरे गणित उदाहरण के आधार पर कुछ प्राप्त करने में दिलचस्पी थी (जिज्ञासा से बाहर)। आपका उदाहरण उपयोगी है :) – abcd

2

आप वास्तव में ViewPatterns उपयोग कर सकते हैं एक सूची के अंत में मिलान पैटर्न क्या करना है, तो चलो करते हैं:

{-# LANGUAGE ViewPatterns #-} 

और हम पैटर्न मैच से पहले सूची पीछे करके अपने last1 और last2 को फिर से परिभाषित। यह ओ (एन) बनाता है, लेकिन यह एक सूची के साथ अपरिहार्य है।

last1 (reverse -> (x:_)) = x 

वाक्य रचना

mainFunction (viewFunction -> pattern) = resultExpression

के लिए

mainFunction x = case viewFunction x of pattern -> resultExpression

तो

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

यह last1 एक सूची देता है यदि सूची खाली है, जैसे मूल last करता है।

*Main> last []
*** Exception: Prelude.last: empty list
*Main> last1 []
*** Exception: Patterns.so.lhs:7:6-33: Non-exhaustive patterns in function last1

ठीक है, ठीक है, वास्तव में नहीं है, लेकिन हम बदल सकते हैं कि

last1 _ = error "last1: empty list" 

जो आप

*Main> last1 []देता जोड़कर *** Exception: last1: empty list

हम निश्चित रूप से last2 के लिए एक ही चाल का उपयोग कर सकते हैं:

last2 (reverse -> (_:x:_)) = x 
last2 _ = error "last2: list must have at least two elements" 

लेकिन यह परिभाषित करने के लिए

maybeLast2 (reverse -> (_:x:_)) = Just x 
maybeLast2 _ = Nothing 

आप के साथ इस रास्ते पर ले जा सकता है अच्छे होगा उदाहरण last4 के लिए:

last4 (reverse -> (_:_:_:x:_)) = x 

और आप देख सकते हैं कि reverse व्यूपार्टन, का उपयोग करके हमने (_:_:_:x:_) से (ignore1st,ignore2nd,ignore3rd,get4th,ignoreTheRestOfTheList) से (ignoreLast,ignore2ndLast,ignore3rdLast,get4thLast,ignoreTheRestOfTheList) पर सेमेन्टिक्स बदल दिए हैं।

आप ध्यान दें कि मेथेमेटिका में, अंडरस्कोर की संख्या से संकेत मिलता है तत्वों की संख्या अनदेखा किया जा रहा प्रयोग किया जाता है। हास्केल में, हम सिर्फ एक _ उपयोग करते हैं, लेकिन यह किसी भी नजरअंदाज कर दिया मूल्य के लिए इस्तेमाल किया जा सकता है, और असममित सूची निर्माता : की उपस्थिति में, अर्थ विज्ञान है, जो पक्ष आप पर कर रहे हैं पर निर्भर करते हैं a:b में ऐसा है, a एक तत्व मतलब है और एक सूची (जो अपने आप कर सकते थे किया c:d क्योंकि : सही साहचर्य है - a:b:c मतलब है a:(b:c)) b होना चाहिए चाहिए। यही कारण है कि किसी भी सूची पैटर्न में एक अंतिम अंडरस्कोर ignoreTheRestOfTheList reresents, और reverse viewfunction की उपस्थिति में, उस सूची के सामने तत्वों की अनदेखी का मतलब है।

मैथमैटिका में हुड के नीचे छिपी हुई पुनरावृत्ति/बैकट्रैकिंग दृश्य के साथ यहां स्पष्ट है फंक्शन reverse (जो एक पुनरावर्ती कार्य है)।

+0

धन्यवाद, आपकी व्याख्या सहायक थी! :) – abcd

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