Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何跟踪简单猜测游戏中的猜测次数(Haskell)_Haskell_Random_State - Fatal编程技术网

如何跟踪简单猜测游戏中的猜测次数(Haskell)

如何跟踪简单猜测游戏中的猜测次数(Haskell),haskell,random,state,Haskell,Random,State,在过去的几周里,我一直在尝试独立学习Haskell。目前,我正在尝试实现一个愚蠢的小猜谜游戏,其中计算机选择一个随机数,用户尝试猜它。如果用户错了,程序会告诉用户答案是高还是低,并允许用户猜测,直到他们猜对为止。我已经让它工作了,但是我想添加一个功能,可以跟踪用户在每个游戏中的猜测次数,并在用户猜对后向用户报告该数字 从命令式的背景来看,自然要做的事情是让计数器在用户每次猜测时递增,但在Haskell中,你不能真正做到这一点(至少看起来一切的无状态性和不变性都会阻止这一点) 我曾想过让getGu

在过去的几周里,我一直在尝试独立学习Haskell。目前,我正在尝试实现一个愚蠢的小猜谜游戏,其中计算机选择一个随机数,用户尝试猜它。如果用户错了,程序会告诉用户答案是高还是低,并允许用户猜测,直到他们猜对为止。我已经让它工作了,但是我想添加一个功能,可以跟踪用户在每个游戏中的猜测次数,并在用户猜对后向用户报告该数字

从命令式的背景来看,自然要做的事情是让计数器在用户每次猜测时递增,但在Haskell中,你不能真正做到这一点(至少看起来一切的无状态性和不变性都会阻止这一点)

我曾想过让getGuess和GiveHights函数接受一个额外的参数,该参数表示到目前为止的猜测次数(我们称之为numGuesses),并且在每次调用这些方法时,都使用pass(numguesss+1)。但我无法让它发挥作用(更不用说我甚至不知道这是否有效)

我的代码如下。任何建议都将不胜感激。我主要是在寻找想法,但也可以随意发布实际代码。另外,如果我的代码很差劲,请随时告诉我,如果您注意到任何令人发指的事情,我可以如何改进它(我只在功能上编程了几个星期!)

导入系统。随机
导入系统.IO
进口管制
main=do

gen事实上,您可以实现您所考虑的计数方法,但仍然需要显式地传递状态。但在这种情况下,这一点也不麻烦。事实上,对于helper函数来说,这是一种非常常见的模式,实际使用
状态
monad会有点过头

我所指的模式通常如下所示:

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
导入系统随机(randomRIO)
导入控件。应用程序(())
导入控制.Monad(何时)
导入Text.Printf(Printf)
游戏::Int->Int->IO()
playGame回答curGuesses=do
putStrLn“你猜怎么着?”
putStr“>”
猜Int->IO()
给出提示回答猜测
|答案>猜测=putStrLn“更高!”
|否则=putStrLn“更低!”
getGuessFromUser::IO Int
getGuessFromUser=do
阅读getLine
main::IO()
main=do

答案为猜测次数添加一个额外的参数正是从功能上做这类事情的方式

基本的功能思维模式是,如果你有一个函数,它需要根据“某物”的不同值做出不同的行为,那么某物就是该函数的一个参数。这是纯洁的简单结果;函数必须始终为相同的输入返回相同的内容


当你使用更先进的技术时,有各种各样的方法“隐藏”额外的参数,使你不必显式地写/传递它们;这基本上正是
状态
单子所做的,而思考
IO
单子的一种方式是它正在做类似的事情。但是,虽然你对函数式编程还不熟悉,但习惯这种思维方式可能更有帮助;通过参数将信息传递给正在调用的函数,并通过参数接收信息。你不能求助于命令式技巧,只将信息留在某个外部位置(例如计数器的值),在那里你知道你调用的函数将查找它(甚至修改它)。

你的想法(添加一个参数来计算已经进行了多少次猜测)是完美的。当您尝试它时,出现了什么问题?我想解决代码中与实际问题无关的一个奇怪的地方(这就是为什么这是一个单独的注释)。如果使用的是显式种子,则应使用
setStdGen
放回由
randomR
返回的新种子,而不是使用
newStdGen
完全重新播种。(事实上,在理想情况下,你根本不会重新播种,而是在程序的不同运行中保存种子。如果你感兴趣,可以问我为什么。)或者,你可以使用
randomRIO
跳过
getStdGen/randomR/setStdGen
序列,它封装了这个模式。@NicolasDudebout,简短的版本是PRNG只保证从单个种子开始的长序列;我不知道有谁能保证不同种子产生的第一个数字的顺序。在ghci中试试这个例子:
map(fst.random.mkStdGen)[0..10]:[Bool]
,它会产生看起来不太随机的
[True,True,True,True,True,True,True,True]
@DanielWagner-只要看看序列,你怎么能确定这不是随机的?;)我遇到的问题是,在我的理解中,块是否返回IO()类型的内容。我构造函数的方式要求我同时需要getGuess和giveHights函数返回numguesss值(并且它们都需要被传递),因为它们是相互递归的。我试图通过使用return将numgueses封装为一个IO操作来解决这个问题,但这似乎很麻烦,我无法让它工作。你也可以使用
if guess==answer然后do。。。或者做…
而不是在
语句时有两个类似的
。是的,我知道,但是如果可能的话,我喜欢远离if-then-else。只是个人喜好的问题。@谢谢你的详细回复。我现在明白了,我的主要缺陷是我的相互递归givehipts和getGuesses函数,这让我感到非常恶心。您的组织很有意义。@mkfarrow:相互递归并不坏,只是这种方式好一点。你会喜欢我吗
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