मैं अभी भी हैकेल सीख रहा हूं और मुझे एक ट्यूटोरियल मिला जो निम्नलिखित जल्लाद सरल प्रोग्राम का उपयोग करके आईओ अवधारणाओं का परिचय देता है

import System.IO
import System.Random

main = do
  handle <- openFile "enable1.txt" ReadMode 
  contents <- hGetContents handle           
  gen <- getStdGen                          
  let words = map init (lines contents)     
      (n, _) = randomR(0, (length words) - 1) gen :: (Int, StdGen) 
      word = words !! n                                         
  play word (map (\x -> '_') word) 6        
  build the print the string
  hClose handle                           

play word known guesses
  | word == known = do
      putStrLn known
      putStrLn "You win!!"
  | guesses == 0 = do
      putStrLn known
      putStrLn ("You lose. the word was " ++ word ++ ".")
  | otherwise    = do
      putStrLn known
      putStrLn ("You have " ++ guesses ++ "guesses left.")
      line <- getLine
      let (newKnown, newGuesses) = handle (head line) word known guesses
      play word newKnown newGuesses

    --putStrLn (handle (head line) word)

handle letter word known guesses
  | letter `elem` word = (zipWith (\w k -> if w == letter then w else k) word known, guesses)
  | otherwise          = (known, guesses - 1)

Enable1.txt एक स्थानीय फ़ाइल है जिसमें बहुत सारे शब्द हैं। मैं रनहास्किल का उपयोग करके फ़ाइल चलाता हूं और मुझे निम्न त्रुटि मिलती है:

:~/Documents/atom/haskell$ runhaskell hangman.hs 

hangman.hs:22:36: error:
    • No instance for (Num [Char]) arising from the literal ‘6’
    • In the third argument of ‘play’, namely ‘6’
      In a stmt of a 'do' block: play word (map (\ x -> '_') word) 6
      In the expression:
        do { handle <- openFile "enable1.txt" ReadMode;
             contents <- hGetContents handle;
             gen <- getStdGen;
             let words = map init (lines contents)
                 (n, _) = ...
                 ....;
             .... }

hangman.hs:30:16: error:
    • No instance for (Num [Char]) arising from the literal ‘0’
    • In the second argument of ‘(==)’, namely ‘0’
      In the expression: guesses == 0
      In a stmt of a pattern guard for
                     an equation for ‘play’:
        guesses == 0

hangman.hs:37:36: error:
    • No instance for (Num [Char]) arising from a use of ‘handle’
    • In the expression: handle (head line) word known guesses
      In a pattern binding:
        (newKnown, newGuesses) = handle (head line) word known guesses
      In the expression:
        do { putStrLn known;
             putStrLn ("You have " ++ guesses ++ "guesses left.");
             line <- getLine;
             let (newKnown, newGuesses) = handle (head line) word known guesses;
             .... }

क्या कोई मुझे इस मुद्दे को समझने में मदद कर सकता है/इसे कैसे ठीक किया जाए। रनहास्केल --वर्जन रनघक 8.0.2 है

1
Kaliawsfate 15 जून 2018, 21:15

3 जवाब

सबसे बढ़िया उत्तर

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

"विशेषज्ञ" सहित अधिकांश हास्केलर हमेशा टाइप एनोटेशन से कोई भी नया शीर्ष-स्तरीय फ़ंक्शन (या सामान्य रूप से बाध्यकारी) लिखना शुरू करते हैं। यानी foo :: Type1 -> Type2 -> ... -> ReturnType लिखकर। वास्तव में, यह कई कारणों से दृढ़ता से अनुशंसित है।

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

दूसरा, यह प्रकार के अनुमान इंजन को अनपेक्षित प्रकारों का अनुमान लगाने से रोकता है। उदाहरण के लिए, इस कोड पर विचार करें।

foo x = "hello" ++ x   -- line A

इसे बिना किसी समस्या के स्वीकार किया जाता है, और GHC द्वारा x को String प्रकार का माना जाता है।

हालाँकि, प्रोग्रामर के दिमाग में x एक पूर्णांक होना चाहिए था, और इसलिए, बाद में, प्रोग्रामर लिखता है

let s = foo 42 in ...  -- line B

और जीएचसी शिकायत करता है कि 42 String नहीं है। या इससे भी बदतर, कि Num String संतुष्ट नहीं हो सकता, जिसका अर्थ है कि एक स्ट्रिंग एक संख्यात्मक प्रकार में नहीं है। अब प्रोग्रामर हैरान है क्योंकि जीएचसी समस्या के रूप में लाइन बी को इंगित करता है, लेकिन वह कोड प्रोग्रामर को ठीक दिखता है। "मैं एक पूर्णांक पास कर रहा हूं, foo एक पूर्णांक की अपेक्षा करता है, यह अजीब स्ट्रिंग त्रुटि कहां से आ रही है?!?"

यह संकलक की गलती नहीं है - यह जानने का कोई तरीका नहीं है कि लाइन ए में कोड गलत था। हालांकि, अगर प्रोग्रामर ने कंपाइलर को लाइन ए के आसपास बताया, कि x का इरादा एक पूर्णांक होना था, तो यह वास्तव में कंपाइलर गलती होगी! कंपाइलर को अब लाइन ए में त्रुटि के बारे में शिकायत करनी चाहिए! और वास्तव में, यह करता है: यहां एक जीएचसीआई त्वरित परीक्षण है।

>  foo :: Int -> String ; foo x = "hello" ++ x
error:
    • Couldn't match expected type ‘[Char]’ with actual type ‘Int’
    • In the second argument of ‘(++)’, namely ‘x’
      In the expression: "hello" ++ x
      In an equation for ‘foo’: foo x = "hello" ++ x

आह-हा! ++ एक स्ट्रिंग चाहता है, लेकिन x एक पूर्णांक है। तो हमें इसे बदलना होगा

> foo :: Int -> String ; foo x = "hello" ++ show x

अब, कोई त्रुटि उत्पन्न नहीं होती है।

सामान्य तौर पर, जब कोडिंग और कुछ गलती करते हैं, तो GHC को अनपेक्षित प्रकार के अनुमान के लिए प्रेरित किया जा सकता है, जिससे बाद में त्रुटिपूर्ण त्रुटियां हो सकती हैं, जो सही कोड की ओर इशारा करती हैं। ऐसे मामलों में, प्रोग्रामर के इरादे के बारे में संकलक को सूचित करते हुए, अधिक से अधिक प्रकार के एनोटेशन जोड़ने के लिए एक सामान्य तकनीक है, ताकि जीएचसी अधिक सार्थक त्रुटियां उत्पन्न कर सके। आखिरकार, जीएचसी और प्रोग्रामर सहमत हैं कि कुछ गड़बड़ है, और बग को ठीक किया जा सकता है।

3
chi 15 जून 2018, 22:53

आपको त्रुटियां मिल रही हैं क्योंकि कार्यक्रम में प्रकार असंगत हैं।

  • No instance for (Num X) का अर्थ है कि "X किसी प्रकार की संख्या नहीं है"।
  • [Char] एक स्ट्रिंग का प्रकार है (String इसके लिए एक उपनाम है)।
  • तो आपकी त्रुटि का मतलब है कि कुछ स्ट्रिंग और संख्या के रूप में उपयोग किया जा रहा है।

आपके कोड को देखने पर मैं देख सकता हूँ कि play में आपके पास है

  • "You have " ++ guesses ++ "guesses left." जिसका अर्थ है कि guesses एक स्ट्रिंग होना चाहिए, ताकि अन्य स्ट्रिंग्स के साथ जोड़ा जा सके।
  • guesses == 0 जिसका अर्थ है कि guesses एक संख्या होनी चाहिए।

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

किसी संख्या को प्रिंट करने के लिए स्ट्रिंग में बदलने के लिए, आप show फ़ंक्शन का उपयोग कर सकते हैं:

"You have " ++ show guesses ++ "guesses left."
2
Kevin Reid 15 जून 2018, 21:27

आप (++) एक String और एक अंक प्रकार नहीं कर सकते। इससे पहले कि आप इसे किसी अन्य स्ट्रिंग से जोड़ सकें, आपको संख्या को String में बदलने के लिए पहले फ़ंक्शन show का उपयोग करना चाहिए।

आपके कोड में, पैरामीटर word और known कुछ प्रकार के हैं Num a => a, लेकिन (++) केवल दो String (यानी [Char]) को एक के रूप में स्वीकार करते हैं। पैरामीटर (सटीक होने के लिए, यह एक ही प्रकार के तत्वों की दो सूचियों को स्वीकार करता है, और चूंकि आपने पहले ही एक String लागू कर दिया है, अन्य पैरामीटर भी एक String होना चाहिए)। तो आपको word को show word से बदलना चाहिए, और known के लिए भी ऐसा ही करना चाहिए।

1
Krantz 16 जून 2018, 05:24