2009-03-26 16 views
5

में putStrLn को कॉल करने का प्रयास करने में त्रुटि मैं एक हैकेल फ़ंक्शन में 'प्रिंट आउट' फ़ंक्शन कॉल डालने का प्रयास कर रहा हूं।हैकेल: फ़ंक्शन

(एक साधारण डीबग संदेश)।

नीचे मेरा कोड और संकलक (त्रुटि 6.10) से त्रुटि संदेश है।

मुझे समझ में नहीं आता कि यह पुटस्ट्र कॉल और खाली सरणी क्यों लंप रहा है।

खाली सरणी उस विशेष मामले के लिए वापसी मूल्य है (प्रिंट आउट संदेश वास्तव में अभी केवल एक स्टब है)।

कोई विचार क्यों यह काम नहीं कर रहा है?

धन्यवाद

मेरे कोड:

 
isAFactor :: Integer -> Integer -> Bool 
isAFactor x y = x `mod` y == 0 

findFactors :: Integer -> Integer -> [Integer] 
findFactors counter num = 
    let quotient = div num 2 
    in 
     if(counter > quotient) 
      then do 
       putStrLn ("factorList is : " ++ show quotient) (*** Line 10***) 
       [] 
     else if(isAFactor num counter) 
      then [counter] ++ [quotient] ++ findFactors (counter + 1) num 
     else 
      findFactors (counter + 1) num 

GHC

 
    test.hs:10:4: 
    Couldn't match expected type `[a] -> [Integer]' 
      against inferred type `IO()' 
    In the expression: 
     putStrLn ("factorList is : " ++ show quotient) [] 
    In the expression: 
     do putStrLn ("factorList is : " ++ show quotient) [] 
    In the expression: 
     if (counter > quotient) then 
      do putStrLn ("factorList is : " ++ show quotient) [] 
     else 
      if (isAFactor num counter) then 
        [counter] ++ [quotient] ++ findFactors (counter + 1) num 
      else 
       findFactors (counter + 1) num 
+0

मुझे विश्वास है कि ऐसा इसलिए है क्योंकि findFactors एक शुद्ध कार्य है, इसलिए इसका कोई दुष्प्रभाव नहीं हो सकता है (जैसे आईओ)। हास्केल सब कुछ है। मुझे नहीं पता कि आपके फ़ंक्शन को डीबग करने के बारे में कैसे जाना है, हालांकि। सी ++ में मैं हर समय डीबग-लॉगिंग का उपयोग करता हूं। –

+0

"डू" का मतलब यह नहीं है कि इसका क्या अर्थ है। यह मोनैड अनुक्रमण के लिए सिंटैक्स चीनी है; आप वास्तव में हास्केल में कुछ भी नहीं कर सकते हैं। :-) – ShreevatsaR

उत्तर

18

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

हालांकि यह शुद्धता तोड़ना संभव है और यह डिबगिंग में उपयोगी हो सकता है। मॉड्यूल Debug.Trace पर एक नज़र डालें। वहां आपको एक समारोह trace :: String -> a -> a मिलेगा। आप इस तरह अपने कोड में उपयोग कर सकते हैं:

import Debug.Trace 

isAFactor :: Integer -> Integer -> Bool 
isAFactor x y = x `mod` y == 0 

findFactors :: Integer -> Integer -> [Integer] 
findFactors counter num = 
    let quotient = div num 2 
    in 
     if(counter > quotient) 
       then trace ("factorList is: " ++ show quotient) [] 
     else if(isAFactor num counter) 
      then [counter] ++ [quotient] ++ findFactors (counter + 1) num 
     else 
      findFactors (counter + 1) num 

टिप्पणी के रूप में सुझाव दिया:

हास्केल भी एक lazy भाषा है। वास्तव में परिणाम की आवश्यकता होने से पहले एक अभिव्यक्ति का मूल्यांकन नहीं किया जाता है। ट्रेस फ़ंक्शन का उपयोग आलसी सेटिंग में थोड़ा उलझन में हो सकता है क्योंकि ट्रेस संदेश स्क्रीन पर मुद्रित होने पर यह समझना हमेशा आसान नहीं होता है (यदि यह बिल्कुल मुद्रित होता है)।

जैसा कि हैकेल एक बहुत ही अलग तरह की भाषा है, यह संभवतः एक समान तरीके से प्रोग्रामों को आजमाने और विकसित करने के लिए सबसे अच्छा है। trace और इसी तरह की "अस्पष्ट" संरचनाओं का उपयोग करने के बजाय अपने कार्यों के बारे में तर्क देने का प्रयास करें। हैकल्स शक्तिशाली प्रकार प्रणाली का लाभ उठाने के लिए जानें और उदाहरण के लिए (0 उदाहरण के लिए) QuickCheck टाइप फ़ंक्शन को पार करने के बाद अपने फ़ंक्शन का परीक्षण करने के लिए जानें। monadic ऑपरेटरों के साथ (कभी कभी बयान बुलाया)

+0

यह ध्यान देने योग्य है कि हास्केल आलसी भाषा है, इसलिए इन 'ट्रेस' कॉल भी आलसी हो जाते हैं। चूंकि संचालन की कोई स्पष्ट अनुक्रम नहीं है, इसलिए 'ट्रेस' की कॉल ऑर्डर से बाहर हो सकती है या बिल्कुल भी नहीं हो सकती है। याद रखें कि आप एक आलसी भाषा से निपट रहे हैं, डीबगिंग करते समय भी। –

3

स्पष्टीकरण

समस्या यह है कि हास्केल में आईओ monadic है के साथ अपडेट किया, do के साथ शुरुआत ब्लॉक monadic भाव के संयोजन के लिए एक वाक्यात्मक चीनी है। इस मामले में, प्रश्न में मोनड आईओ मोनैड है, जिसे कॉल से आरआरएलएनएन के लिए अनुमानित किया जा सकता है। []do ब्लॉक की दूसरी पंक्ति में वास्तव में पूरे डॉक ब्लॉक के मूल्य नहीं है, बल्कि इसे putStrLn का अंतिम तर्क बताया गया है; यह नहीं कि यह एक दूसरा तर्क स्वीकार करता है, लेकिन संकलक इसे समझने के बिंदु तक भी नहीं पहुंचता है, क्योंकि यह आपके द्वारा उद्धृत प्रकार की त्रुटि के साथ पहले समाप्त हो जाता है। उस पंक्ति को कमांड बनाने के लिए, आपको इसके सामने, उदाहरण के लिए, एक और monadic फ़ंक्शन वापस करना होगा (यानी, return [])। मैं यह नहीं कह रहा हूं, हालांकि, इससे आपको अपनी समस्या का समाधान करने में मदद मिलेगी।

प्रकार त्रुटि इस तथ्य से उत्पन्न होती है कि आईओ monadic अभिव्यक्ति हमेशा IO _ प्रकार है; आपके मामले में, do ब्लॉक में इस प्रकार का भी है, जो कि हस्ताक्षर में निर्दिष्ट प्रकार [Integer] के साथ स्पष्ट रूप से असंगत है।

सामान्य रूप से, क्योंकि हास्केल मैनाडिक आईओ के साथ एक शुद्ध कार्यात्मक भाषा है, एक बार जब आप आईओ मोनैड के अंदर होते हैं, तो इसका कोई रास्ता नहीं है, यह संक्रामक है। यानी, यदि किसी फ़ंक्शन में do इसमें आईओ ऑपरेशंस के साथ ब्लॉक है, तो इसके हस्ताक्षर में IO _ प्रकार आवश्यक होगा, और इस प्रकार इस फ़ंक्शन का आविष्कार करने वाले अन्य सभी कार्यों का हस्ताक्षर भी होगा। (अन्य मोनैड "बाहर निकलने" फ़ंक्शन प्रदान करते हैं, लेकिन आईओ मोनड नहीं करता है।)

+0

यह वास्तव में व्याख्या नहीं किया गया है क्योंकि putStrLn का अंतिम तर्क है? यह दूसरा तर्क है (>> =)। ब्लॉक जरूरी नहीं हैं IO(), ब्लॉक के कई अलग-अलग प्रकार हैं, जिनमें [ए] भी शामिल है! – cthulahoops

+0

आपको यहां कई गलत धारणाएं मिली हैं। मुझे एक ईमानदार पद को कम करने से नफरत है, लेकिन इससे पता चलता है कि यह इससे ज्यादा अस्पष्ट है। –

+0

@cthulahoops: त्रुटि संदेश 'अभिव्यक्ति में "putStrLn (" कारक सूची है: "++ दिखाएं उद्धरण) []" ऐसा लगता है कि मेरी व्याख्या सही है। –

9

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

तो तुम 1n/2 अप करने के लिए से प्रत्येक संख्या को देखकर, अगर यह n का एक पहलू है देखने के लिए जाँच और उन की एक सूची का निर्माण करके दी गई संख्या n के सभी कारकों लगाना चाहते हैं।

आपका संस्करण (कम से कम संशोधनों के साथ यह काम करने के लिए प्राप्त करने के लिए):

findFactors :: Integer -> Integer -> [Integer] 
findFactors counter num = 
    let quotient = div num 2 
    in 
     if(counter > quotient) 
      then [] 
     else if(isAFactor num counter) 
      then [counter] ++ findFactors (counter + 1) num 
     else 
      findFactors (counter + 1) num 

स्वरूपण परिवर्तन के एक जोड़े को यह थोड़ा अधिक पठनीय बनाने के लिए:

findFactors :: Integer -> Integer -> [Integer] 
findFactors counter num 
    | counter > div num 2 = [] 
    | otherwise = if num `isAFactor` counter 
       then counter:findFactors (counter+1) num 
       else findFactors (counter + 1) num 

यह ठीक है, लेकिन यह है कुछ तरीकों से आदर्श से कम। सबसे पहले, यह प्रत्येक बार findFactors कहलाता है, जो n/2 डिवीजनों (हालांकि ghc -O2 को यह महसूस होता है और केवल एक बार इसकी गणना करता है) को प्रतिबिंबित करता है। दूसरा, यह हर जगह उस काउंटर वैरिएबल से निपटने के लिए परेशान है। तीसरा, यह अभी भी बहुत जरूरी है।

समस्या को देखने का एक और तरीका 1 से n/2 तक पूर्णांक की सूची लेना होगा और केवल n के कारकों के लिए फ़िल्टर करना होगा। यह सुंदर सीधे हास्केल में तब्दील हो:

findFactors :: Integer -> [Integer] 
findFactors num = filter (isAFactor num) [1..(num `div` 2)] 

यह एक आश्चर्य के रूप में आ सकता है कि यह ऊपर संस्करण के समान प्रदर्शन लक्षण है खोजने के लिए। Haskell को पूरी सूची के लिए n/2 तक स्मृति को आवंटित करने की आवश्यकता नहीं है, यह केवल प्रत्येक मान को आवश्यकतानुसार उत्पन्न कर सकता है।

7

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

Couldn't match expected type `[a] -> [Integer]' 
     against inferred type `IO()' 
In the expression: 
    putStrLn ("factorList is : " ++ show quotient) [] 

मैंने अन्य सभी "अभिव्यक्ति में" भागों को याद किया है; वे सिर्फ अधिक से अधिक संलग्न संदर्भ दिखाते हैं।

हास्केल में सब कुछ एक अभिव्यक्ति है, इसलिए इसलिए सब कुछ एक प्रकार है। इसमें "putStrLn" जैसी कुछ शामिल है। आप लिखते हैं, तो ": टी putStrLn" GHCi में आप देखेंगे यह उत्तर:

putStrLn :: String -> IO() 

जिसका मतलब है कि putStrLn एक समारोह है कि एक स्ट्रिंग लेता है और एक "IO कार्रवाई", जो इस मामले में कार्रवाई की है देता है स्क्रीन पर संदेश डालना।आपके कोड में आपने "putStrLn" एक स्ट्रिंग दी है, इसलिए संकलक ने अनुमान लगाया कि अभिव्यक्ति "putStrLn (सामान)" प्रकार "IO()" था। यह संकलक त्रुटि संदेश का "अनुमानित प्रकार" भाग है।

इस बीच संकलक भी दूसरी दिशा में प्रकार निष्कर्ष कर रहा था, में बाहर से। अन्य बातों के बीच यह देखा है कि इस "putStrLn (सामान)" अभिव्यक्ति लग रहा था जो एक खाली सूची के लिए लागू किया जा सकता है, टाइप करें "[ए]" (यानी कुछ की एक सूची, हम नहीं जानते कि क्या)। इसके अलावा पूरी अभिव्यक्ति का परिणाम "[इंटीजर]" प्रकार का होना चाहिए। इसलिए अभिव्यक्ति "putStrLn (सामान)" पूर्णांक की सूची में "[]" को चालू करने के लिए एक फ़ंक्शन होना चाहिए, जिसका प्रकार "[a] -> [Integer]" लिखा गया है। यह त्रुटि संदेश का "अपेक्षित प्रकार" भाग है।

इस बिंदु पर संकलक ने निष्कर्ष निकाला कि यह इन दो प्रकारों से मेल नहीं खा सकता है, इसलिए यह त्रुटि की सूचना दी।

"की उम्मीद नहीं मेल खा सकते हैं प्रकार 'फू' अनुमानित प्रकार 'बार' के खिलाफ" शायद आप जब हास्केल संकलित करने के लिए कोशिश कर पाने के आम त्रुटि संदेश है, इसलिए इसे पढ़ सकते हैं और यह समझने की कोशिश कर अपने लायक। अनुमानित प्रकार को देखें और उद्धृत अभिव्यक्ति का किस भाग में उस प्रकार का पता लगाने का प्रयास करें। फिर यह पता लगाने की कोशिश करें कि कंपाइलर को आस-पास के कोड को देखकर कुछ और क्यों अपेक्षित था।

+0

+1, त्रुटि संदेश की अच्छी व्याख्या। मैं यह नहीं समझ सका कि कोड ने त्रुटि की सूचना कैसे दी। जब तक मुझे एहसास हुआ कि प्रश्नकर्ता ने "लाइन 10" टिप्पणी डालने के लिए एक लाइन ब्रेक डाला। –