2012-08-08 16 views
7

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

एक अनिवार्य पृष्ठभूमि से आ रहा है, करने के लिए प्राकृतिक चीज एक काउंटर होना चाहिए जो हर बार जब उपयोगकर्ता अनुमान लगाता है, लेकिन आप वास्तव में हास्केल में ऐसा नहीं कर सकते हैं (कम से कम यह स्टेटलेसनेस जैसा लगता है और सब कुछ की अपरिवर्तनीयता उस को रोक देगा)।

मैंने गेटगुएस बनाने और देने के विचार के साथ खिलवाड़ किया है। हंट्स फ़ंक्शंस एक अतिरिक्त पैरामीटर लेते हैं जो अब तक अनुमानों की संख्या का प्रतिनिधित्व करता है (चलिए इसे numGuesses कहते हैं), और, उन तरीकों से प्रत्येक कॉल पर, पास (numGuesses + 1) । लेकिन मैं इसे काम नहीं कर सका (उल्लेख नहीं करना कि मुझे यह भी पता नहीं है कि यह काम करेगा या नहीं)।

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

import System.Random 
    import System.IO 
    import Control.Monad 

    main = do 
     gen <- getStdGen 
     let (ans,_) = randomR (1,100) gen :: (Int,StdGen) 
     putStrLn $ "I'm thinking of a number between 1 and 100..." 
     getGuess ans 
     putStrLn "You guessed it in __ guesses!" 
     putStr "Play again? " 
     hFlush stdout 
     desire <- getLine 
     when ((desire !! 0) `elem` ['y','Y']) $ do 
      putStrLn "" 
      newStdGen 
      main 

    getGuess ans = do 
     putStr "Your guess? " 
     hFlush stdout 
     guessStr <- getLine 
     giveHints ans (read guessStr) 

    giveHints ans guess = do 
     when (ans /= guess) $ do 
      if ans > guess 
       then putStrLn "It's higher." 
       else putStrLn "It's lower." 
      getGuess ans 

नोट (मैं केवल कुछ हफ्तों के लिए कार्यात्मक प्रोग्रामिंग कर रहे थे!): मैं hFlush उपयोग कर रहा हूँ stdout क्योंकि मैं लाइन बफरिंग का उपयोग कर रहा हूं और इसके बिना, कुछ इंटरैक्शन का क्रम वह नहीं है जो उम्मीद करेगा।

+3

आपका विचार (पैरामीटर जोड़ना कि कितने अनुमान पहले से ही चले गए हैं) सही है। जब आपने कोशिश की तो क्या गलत हुआ? –

+4

मैं इस कोड में एक अजीब बिट को संबोधित करना चाहता हूं जो वास्तविक प्रश्न से संबंधित नहीं है (यही कारण है कि यह एक अलग टिप्पणी है)। यदि आप एक स्पष्ट बीज का उपयोग कर रहे हैं, तो आपको 'newStdGen' के साथ पूरी तरह से शोध करने के बजाय' setStdGen' का उपयोग करके 'randomR' द्वारा लौटाया गया नया बीज वापस रखना चाहिए। (वास्तव में, एक आदर्श दुनिया में, आपने कार्यक्रम के विभिन्न रनों में बीज को बचाने के बजाय कभी भी शोध नहीं किया था। मुझसे पूछें कि आप रुचि क्यों रखते हैं।) वैकल्पिक रूप से, आप 'getStdGen/randomR/setStdGen को छोड़ सकते हैं 'randomRO' का उपयोग करके अनुक्रम, जो इस पैटर्न को समाहित करता है। –

+1

मुझे रूचि है। क्यूं कर? ;-) –

उत्तर

8

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

पैटर्न मैं बात कर रहा हूँ अक्सर इस तरह दिखता है:

doStuff xs' = go xs' 0 
    where 
    go (x:xs) n = .. etc .. 

कोड यह रहा।

import System.Random  (randomRIO) 
import Control.Applicative ((<$>)) 
import Control.Monad  (when) 
import Text.Printf   (printf) 

playGame :: Int -> Int -> IO() 
playGame answer curGuesses = do 
    putStrLn "What is your guess?" 
    putStr ">" 
    guess <- getGuessFromUser 
    when (guess /= answer) $ do 
     giveHints answer guess 
     playGame answer (curGuesses + 1) 
    when (guess == answer) $ do 
     putStrLn "You guessed it!" 
     printf "You guessed %d times!\n" (curGuesses + 1) 

giveHints :: Int -> Int -> IO() 
giveHints answer guess 
    | answer > guess = putStrLn "It's higher!" 
    | otherwise  = putStrLn "It's lower!" 

getGuessFromUser :: IO Int 
getGuessFromUser = do 
    read <$> getLine 

main :: IO() 
main = do 
    answer <- randomRIO (1, 100) 
    putStrLn "I'm thinking of a number between 1 and 100." 
    playGame answer 0 

नोट्स

  • <$>, fmap
  • मैं randomRIO इस्तेमाल किया के रूप में डैनियल उल्लेख किया है हम पहले से ही आईओ इकाई में हैं के बाद से।
  • मुझे सही आउटपुट प्राप्त करने के लिए विंडोज पर कमांड प्रॉम्प्ट का उपयोग करके hSetBuffering या hFlush का उपयोग करने की आवश्यकता नहीं थी। हालांकि, वाईएमएमवी।
+0

आप 2 समान 'जब' बयानों के बजाय 'if अनुमान == उत्तर भी कर सकते हैं ... और करें ... 'का उपयोग कर सकते हैं। – huon

+0

हां, मुझे पता है, लेकिन अगर मैं संभव हो तो दूर रहना पसंद करता हूं। वरीयता का मामला – identity

+1

@identity विस्तृत प्रतिक्रिया के लिए धन्यवाद। अब मैं देखता हूं कि मेरा मुख्य दोष मेरा पारस्परिक रूप से रिकर्सिव देने वाला संकेत था और GetGuesses फ़ंक्शन, जो मेरे बारे में काफी सकल था। आपका संगठन बहुत समझ में आता है। – mkfarrow

3

अनुमानों की संख्या के लिए एक अतिरिक्त पैरामीटर जोड़ना ठीक है कि आप इस तरह की चीज़ को कार्यात्मक रूप से कैसे करते हैं।

सोच का मूल कार्यात्मक तरीका यह है कि यदि आपके पास कोई ऐसा कार्य है जिसे "कुछ" के विभिन्न मानों के आधार पर अलग-अलग व्यवहार करने की आवश्यकता है, तो यह फ़ंक्शन के लिए कुछ पैरामीटर है। यह शुद्धता का एक साधारण परिणाम है; एक फ़ंक्शन को हमेशा एक ही इनपुट के लिए एक ही चीज़ को वापस करना होगा।

जब आप करने के लिए और अधिक उन्नत तकनीकों वहाँ "छिपा" अतिरिक्त पैरामीटर लिखने/उन्हें स्पष्ट रूप से पारित करने के लिए होने से आप को मुक्त करने के के विभिन्न तरीके हैं मिलता है, यह मूल रूप से State मोनैड करता है, और IO मोनैड के बारे में सोचने का एक तरीका यह है कि यह कुछ ऐसा ही कर रहा है। लेकिन जब आप कार्यात्मक प्रोग्रामिंग के लिए नए होते हैं तो यह सोचने के तरीके के लिए उपयोग करने के लिए शायद अधिक सहायक होता है; आप उस फ़ंक्शन को जानकारी संचारित करते हैं जिसे आप अपने तर्कों के माध्यम से बुला रहे हैं, और इसके तर्कों के माध्यम से जानकारी प्राप्त करते हैं। आप कुछ बाहरी जगहों (जैसे काउंटर का मूल्य) में जानकारी छोड़ने की अनिवार्य चाल का सहारा नहीं ले सकते हैं, जहां आप जानते हैं कि आपके द्वारा कॉल किए जाने वाले फ़ंक्शन को इसकी तलाश होगी (या इसे संशोधित भी करें)।