2017-06-18 6 views
6

मैं हास्केल में कुछ कोड नीचे पोस्ट कर रहा हूं। कोड को एक उदाहरण के रूप में देखें, जिसे मैं उपयोग करने जा रहा हूं, यह बताने के लिए कि मैं क्या जानना चाहता हूं।हास्केल: तर्कों के सभी संयोजनों पर फ़ंक्शन लागू करना

try :: [[Char]] -> [[Char]] -> [[Char]] -> [[Char]] 
try (a:as) (b:bs) (c:cs) | ((checkIfCorrect a b c) == True) = a:b:[c] 
          | otherwise = try as bs cs 

checkIfCorrect :: [Char] -> [Char] -> [Char] -> Bool 
checkIfCorrect a b c = True 

आखिरकार, checkIfCorrect रिटर्न तर्क का केवल एक संयोजन के लिए TruecheckIfCorrect वास्तव में लंबा काम है, इसलिए मैंने यहां विकल्प पोस्ट करने का फैसला किया। उपर्युक्त उदाहरण में, checkIfCorrect फ़ंक्शन को मुद्रित किया गया है (फ़ंक्शन try द्वारा): पहली सूची में पहले [Char], दूसरी सूची में पहले [Char] और पहले [Char] एक तीसरी सूची। यदि पहले संरक्षित समीकरण पूर्ण नहीं होता है, तो कार्य checkIfCorrect पर लागू होता है: दूसरी सूची में दूसरा [Char] ... और इसी तरह। मैं जो पहुंचना चाहता हूं, सभी सूचियों ([[Char]]) से [Char] एस के सभी संयोजनों के लिए फ़ंक्शन checkIfCorrect (फ़ंक्शन try द्वारा) को संबद्ध करना है। मेरा मतलब है कि निम्नलिखित सूची में निम्नलिखित (उदा।): तीसरा [Char], दूसरी सूची में आठवीं [Char], तीसरी सूची में ग्यारहवें [Char] और इसी तरह। हर किसी के साथ हर कोई। मैं उस तक कैसे पहुंच सकता हूं?

+0

आप 'try' को बदलना चाहते हैं ताकि वापसी प्रकार सूची के बजाय 3 मानों का एक टुपल हो। इस तरह यह स्पष्ट है कि आप सूची में बिल्कुल 3 मान होने की उम्मीद करते हैं। – 4castle

उत्तर

5

हाँ, तो आप यह भी सूची समझ के साथ और अधिक सुंदर बना सकते हैं:

try :: [[Char]] -> [[Char]] -> [[Char]] -> [[Char]] 
try as bs cs = head [ [a,b,c] | a <- as, b <- bs, c <- cs, checkIfCorrect a b c ] 
--     \__ __/ \__________ ____________/ \__________ _______/ 
--      v     v       v 
--      yield   enumeration     filter 

इस प्रकार कोड काम करता है: सूची समझ का सही भाग एक "गणन से बाहर होते हैं "भाग (टिप्पणी अनुभाग द्वारा दर्शाया गया)। जब से हम a <- as, b <- bs, c <- cs बारे में यह मतलब है कि aas से किसी भी मूल्य ले जाएगा, और के लिए हर तरह के a, b तो इसका मतलब है कि हर संभव संयोजन उत्सर्जित हो जाएगा bs, आदि के किसी भी मूल्य का समय लगेगा।

अगला वहाँ "फिल्टर" चरण है: वहाँ एक विधेय checkIfCorrect a b c कि बुलाया जाएगा और वह भी तब है कि विधेय रिटर्न True, परिणाम "झुकेंगे" हो जाएगा।

बाईं ओर हम देखते हैं "उपज"। यह बताता है कि फिल्टर सफल होने के बाद सूची में क्या जोड़ा जाना चाहिए (गणना के आधार पर)। यदि ऐसा होता है तो हम उस सूची में [a,b,c] जोड़ते हैं। यदि सफल होने वाली कई ऐसी कॉन्फ़िगरेशन हैं, तो हम कई समाधान वाले एक सूची के साथ समाप्त हो सकते हैं। लेकिन ध्यान दें कि सूची समझ से किया जाता है lazily: तो जब तक आप कम से कम एक ऐसे तत्व के लिए मत पूछो, यह पहला तत्व, और न ही दूसरा, आदि

अब हम भी head आवश्यकता उत्पन्न नहीं करेगा (सूची समझ के सामने)। head :: [a] -> a सूची के पहले तत्व देता है। तो try स्थिति को पूरा करने वाले पहले तत्व को वापस कर देगा।

11

मैं आपको @WillemVanOnsem's code लिखने का एक वैकल्पिक तरीका दिखाना चाहता था। मुझे लगता है कि आप एक हास्केल शुरुआती हैं, इसलिए उम्मीद है कि यह उत्तर आपको एक समृद्ध और सुंदर विचार की एक छोटी झलक देगा जो आप भाषा के साथ प्रगति के रूप में जल्द ही पूरी तरह से सीखेंगे।तो अगर आप इस कोड के बारे में सबकुछ तुरंत समझ नहीं पाते हैं तो बहुत ज्यादा चिंता न करें; मैं बस आपको एक स्वाद देने की कोशिश कर रहा हूँ! , as में प्रत्येक a के लिए प्रत्येक bs में b के लिए:

import Control.Monad (guard) 

try as bs cs = head $ do 
    a <- as 
    b <- bs 
    c <- cs 
    guard $ checkIfCorrect a b c 
    return [a,b,c] 

मैं नेस्टेड छोरों के लिए एक विशेष अंकन के रूप में do अंकन का उपयोग कर रहा हूँ:

एक सूची समझ हमेशा सूची का उपयोग कर इकाई पुनर्निर्मित किया जा सकता है , और प्रत्येक ccs में, हम [a,b,c] उत्पन्न करते हैं यदि checkIfCorrectTrue देता है। सूची comprehensions से अनुवाद सरल है: "गणन" "बांध" guard को <- कॉल में, "फ़िल्टर" रों बारी का उपयोग करते हुए सूची समझ बारी के कुछ हिस्सों, और return रों में "उपज" रों बारी।

अजगर की तरह एक अनिवार्य भाषा में आप इस तरह यह लिख सकते हैं:

def try(as, bs, cs): 
    for a in as: 
     for b in bs: 
      for c in cs: 
       if checkIfCorrect(a, b, c): 
        yield [a,b,c] 

पश्चिमी नव उदार आधिपत्य के तहत राजनीति की तरह, जरूरी कोड धीरे-धीरे दाहिनी ओर जुलूस। इस तरह के "सीढ़ी" कोड वास्तव में अनिवार्य प्रोग्रामिंग (जेएस में "कॉलबैक नरक" के बारे में सोचते हैं) में अक्सर बार-बार फसल डालते हैं, इसलिए इस प्रवृत्ति का सामना करने में मदद के लिए मोनैड का आविष्कार किया गया था। वे इतने उपयोगी साबित हुए कि उनके लिए एक विशेष वाक्यविन्यास का आविष्कार किया गया, अर्थात् do-नोटेशन।

+5

वह अंतिम अनुच्छेद उद्धरण योग्य है। :) – Alec

+0

'चेक IFCorrect (liftM3 (,,) बीएस सीएस के रूप में खोजें) 'शायद यह करने का एक और तरीका होगा, लेकिन उन्हें अपने कार्यों के प्रकार को थोड़ा सा संशोधित करने की आवश्यकता होगी। – 4castle

+0

'उपज' नहीं, लेकिन 'वापसी', केवल * पहले * संयोजन को वापस करने के लिए परीक्षण पास करता है। –

3

जबकि विल्म वान ऑनसेम और ऑर्गाज़ॉयड के दोनों जवाब अच्छे हैं (ऊपर की ओर), आप समस्या के हिस्से को अधिक सामान्यीकृत तरीके से भी संपर्क कर सकते हैं, न केवल सूचियों के लिए।

निम्नलिखित के लिए, आप इन आयात की जरूरत के लिए जा रहे:

import Control.Monad (MonadPlus, mfilter) 
import Data.Maybe (fromMaybe, listToMaybe) 

मैं सवाल समझ रहा हूँ सही ढंग से, आप में से as, bs, और cs सभी संयोजनों की कोशिश करना चाहते हैं। आप आमतौर पर Applicative typeclass के साथ संयोजन की तरह व्यवहार को प्राप्त कर सकते हैं:

combinations = (,,) <$> as <*> bs <*> cs 

(,,) एक समारोह है कि तीन अलग-अलग मूल्यों से ट्रिपल (तीन तत्व tuples) बनाता है।

इस सूची के लिए काम करता है, क्योंकि सूचियों अनुप्रयोगी हैं:

*Prelude> (,,) <$> [1,2] <*> ["foo", "bar"] <*> [True, False] 
[(1,"foo",True),(1,"foo",False),(1,"bar",True),(1,"bar",False),(2,"foo",True),(2,"foo",False),(2,"bar",True),(2,"bar",False)] 

लेकिन यह भी जैसे के लिए काम करता Maybe रों:

try' :: MonadPlus m => ((a, a, a) -> Bool) -> m a -> m a -> m a -> m [a] 
try' predicate as bs cs = 
    tripleToList <$> mfilter predicate combinations 
    where 
    combinations = (,,) <$> as <*> bs <*> cs 
    tripleToList (a, b, c) = [a, b, c] 

आप इस सहायक समारोह पूरी तरह से सामान्य है कि ध्यान देंगे:

*Prelude> (,,) <$> Just 1 <*> Just "foo" <*> Just False 
Just (1,"foo",False) 
इसी के साथ

, अब आप अपने समारोह के मुख्य परिभाषित कर सकते हैं। यह किसी भी MonadPlus किसी भी निहित तत्व a के उदाहरण के लिए काम करता है।

यहाँ कुछ उदाहरण हैं:

*Answer> try' (const True) ["foo", "bar", "baz"] ["qux", "quux", "quuz", "corge"] ["grault", "garply"] 
[["foo","qux","grault"],["foo","qux","garply"],["foo","quux","grault"],["foo","quux","garply"],["foo","quuz","grault"],["foo","quuz","garply"],["foo","corge","grault"],["foo","corge","garply"],["bar","qux","grault"],["bar","qux","garply"],["bar","quux","grault"],["bar","quux","garply"],["bar","quuz","grault"],["bar","quuz","garply"],["bar","corge","grault"],["bar","corge","garply"],["baz","qux","grault"],["baz","qux","garply"],["baz","quux","grault"],["baz","quux","garply"],["baz","quuz","grault"],["baz","quuz","garply"],["baz","corge","grault"],["baz","corge","garply"]] 
*Answer> try' (const False) ["foo", "bar", "baz"] ["qux", "quux", "quuz", "corge"] ["grault", "garply"] 
[] 
*Answer> try' (const True) (Just "foo") (Just "bar") (Just "baz") 
Just ["foo","bar","baz"] 
*Answer> try' (const False) (Just "foo") (Just "bar") (Just "baz") 
Nothing 

आपने ध्यान दिया जाना चाहिए कि अगर predicate हमेशा False देता है, तुम वापस कुछ भी नहीं मिलेगा।सूचियों के लिए, आपको खाली सूची मिलती है; Maybe के लिए, आपको सचमुच Nothing मिलते हैं।

अभी तक यह सभी सामान्य है, लेकिन checkIfCorrect नहीं है। ऐसा लगता है कि आप मिलान करने वाले पहले तत्व प्राप्त करना चाहते हैं। आपको लगता है कि प्राप्त कर सकते हैं checkIfCorrect साथ try' रचना द्वारा: यहाँ

try :: [String] -> [String] -> [String] -> [String] 
try as bs cs = fromMaybe [] $ listToMaybe $ try' isCorrect as bs cs 
    where isCorrect (a, b, c) = checkIfCorrect a b c 

, मैं आदेश checkIfCorrect समारोह uncurry करने के लिए एक निजी isCorrect समारोह बना लिया है। इसके बाद मैंने परिणामी सूची के पहले तत्व को वापस करने के लिए listToMaybe और fromMaybe का संयोजन उपयोग किया है। अन्य उत्तर यहां head का उपयोग करते हैं, लेकिन यदि सूची खाली है तो यह अपवाद फेंकने जा रहा है, इसलिए मैंने इसके बजाय इस संयोजन का उपयोग किया, क्योंकि यह सुरक्षित है।

+0

या 'संयोजन = लिफ्टए 3 (,) बीएस सीएस के रूप में –

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