2012-02-19 14 views
85

में मामलों मैं तीन कार्यों कि एक सूची के n वें तत्व को खोजने के लिए है:गार्ड बनाम अगर-तो-और कुछ बनाम हास्केल

nthElement :: [a] -> Int -> Maybe a 
nthElement [] a = Nothing 
nthElement (x:xs) a | a <= 0 = Nothing 
        | a == 1 = Just x 
        | a > 1 = nthElement xs (a-1) 

nthElementIf :: [a] -> Int -> Maybe a 
nthElementIf [] a = Nothing 
nthElementIf (x:xs) a = if a <= 1 
         then if a <= 0 
          then Nothing 
          else Just x -- a == 1 
         else nthElementIf xs (a-1)       

nthElementCases :: [a] -> Int -> Maybe a 
nthElementCases [] a = Nothing 
nthElementCases (x:xs) a = case a <= 0 of 
          True -> Nothing 
          False -> case a == 1 of 
             True -> Just x 
             False -> nthElementCases xs (a-1) 

मेरी राय में, पहले समारोह सबसे अच्छा कार्यान्वयन है क्योंकि यह है सबसे संक्षिप्त लेकिन क्या अन्य दो कार्यान्वयनों के बारे में कुछ भी है जो उन्हें बेहतर बना देगा? और विस्तार से, आप गार्ड का उपयोग करने के बीच कैसे चयन करेंगे, अगर-तो-और बयान, और मामले?

+5

यदि आप 'एलटी के 0 की तुलना करें -> ...' का उपयोग करते हैं तो आप अपने नेस्टेड 'केस' कथन को तोड़ सकते हैं। ईक्यू -> ... | जीटी -> ... ' – rampion

+5

@ रैंपियन: आपका मतलब है कि मामला 1 की तुलना करें ...' – newacct

उत्तर

97

तकनीकी दृष्टिकोण से, सभी तीन संस्करण समकक्ष हैं।

कहा जा रहा है, शैली के लिए अंगूठे का मेरा नियम है कि यदि आप इसे पढ़ सकते हैं, जैसे कि वह अंग्रेजी था ("जब" | के रूप में पढ़ा, | otherwise के रूप में "अन्यथा" और = के रूप में "है" या "हो") है , आप शायद कुछ सही कर रहे हैं।

if..then..else जब आपके पास एक बाइनरी स्थिति है, या आपको एक ही निर्णय लेने की आवश्यकता है। नेस्ड if..then..else - हास्केल में एक्सपेरियंस बहुत असामान्य हैं, और गार्ड के बजाय लगभग हमेशा इस्तेमाल किया जाना चाहिए।

let absOfN = 
    if n < 0 -- Single binary expression 
    then -n 
    else n 

हर if..then..else अभिव्यक्ति एक गार्ड द्वारा बदला जा सकता है अगर यह एक समारोह के शीर्ष स्तर पर है, और यह आम तौर पर, प्राथमिकता दी जानी चाहिए, क्योंकि आप और अधिक आसानी से तो अधिक मामलों जोड़ सकते हैं:

abs n 
    | n < 0  = -n 
    | otherwise = n 

case..of जब आपके पास एकाधिक कोड पथ है, और प्रत्येक कोड पथ संरचना द्वारा मानी जाती है, यानी पैटर्न मिलान के माध्यम से। आप शायद ही कभी True और False पर मेल खाते हैं।

case mapping of 
    Constant v -> const v 
    Function f -> map f 

गार्ड case..of भाव के पूरक हैं, जिसका अर्थ है कि आप एक मूल्य के आधार पर जटिल निर्णय करने के लिए, पहले निर्णय अपने इनपुट की संरचना पर निर्भर करते हैं, और तो में मूल्यों पर निर्णय लेने की जरूरत है कि संरचना।

handle ExitSuccess = return() 
handle (ExitFailure code) 
    | code < 0 = putStrLn . ("internal error " ++) . show . abs $ code 
    | otherwise = putStrLn . ("user error " ++)  . show  $ code 

बीटीडब्ल्यू। एक शैली टिप के रूप में, हमेशा एक = के बाद या एक | से पहले एक नई पंक्ति बनाने यदि =/| के बाद सामान को एक पंक्ति के लिए बहुत लंबा है, या किसी अन्य कारण से अधिक लाइनों का उपयोग करता है:

-- NO! 
nthElement (x:xs) a | a <= 0 = Nothing 
        | a == 1 = Just x 
        | a > 1 = nthElement xs (a-1) 

-- Much more compact! Look at those spaces we didn't waste! 
nthElement (x:xs) a 
    | a <= 0 = Nothing 
    | a == 1 = Just x 
    | otherwise = nthElement xs (a-1) 
+1

"आप शायद ही कभी 'सत्य' और 'गलत' पर मेल खाते हैं, क्या आप ऐसा करेंगे जहां आप ऐसा करेंगे? आखिरकार, इस तरह का निर्णय _ ifways_ 'if' के साथ किया जा सकता है, और गार्ड के साथ भी। – leftaroundabout

+0

ईजी। 'केस (फू, बार, बाज) (सही, गलत, झूठा) -> ... – dflemstr

+0

@dflemstr क्या कोई और सूक्ष्म मतभेद नहीं हैं उदा। रक्षकों को मोनाडप्लस की आवश्यकता होती है और यदि मोनैड का एक उदाहरण लौटाता है, तो क्या नहीं? किंतु मुझे यकीन नहीं है। –

21

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

nthElement xs n = guard (n > 0) >> listToMaybe (drop (n-1) xs) 
1

यह केवल आदेश देने का मामला है, लेकिन मुझे लगता है कि यह बहुत पठनीय है और गार्ड के समान संरचना है।

nthElement :: [a] -> Int -> Maybe a 
nthElement [] a = Nothing 
nthElement (x:xs) a = if a < 1 then Nothing else 
         if a == 1 then Just x 
         else nthElement xs (a-1) 
पिछले की जरूरत नहीं है किसी और

और अगर बाद से वहाँ कोई अन्य संभावनाओं है, यह भी कार्यों "अंतिम उपाय मामले" मामले में आप कुछ भी याद नहीं होनी चाहिए।

+0

नेस्टेड अगर-स्टेटमेंट एक विरोधी पैटर्न हैं जब आप केस गार्ड का उपयोग कर सकते हैं। – user76284