Haskell 用foldM和State编写一个简单函数
我试图编写一个小函数,它基本上遍历一系列问题,对于每个问题,提示符将等待用户的响应,如果答案正确,则在分数上加1,如果答案错误,则不做任何操作 我认为如果我只需要记录分数,使用foldM就足够了,但是我还想打印每个问题在列表中的位置,比如“问题1:”等等 使用状态单子有助于跟踪分数和位置吗? 除此之外,我很想和国家队练习 以下是当前代码: 每个问题都是一个包含字符串和答案的元组Haskell 用foldM和State编写一个简单函数,haskell,Haskell,我试图编写一个小函数,它基本上遍历一系列问题,对于每个问题,提示符将等待用户的响应,如果答案正确,则在分数上加1,如果答案错误,则不做任何操作 我认为如果我只需要记录分数,使用foldM就足够了,但是我还想打印每个问题在列表中的位置,比如“问题1:”等等 使用状态单子有助于跟踪分数和位置吗? 除此之外,我很想和国家队练习 以下是当前代码: 每个问题都是一个包含字符串和答案的元组 import Control.Monad import Control.Concurrent import Syste
import Control.Monad
import Control.Concurrent
import System.Exit
qs =
[( "question"
,["1"] --number of the correct answer, from 1 to 4
]
main =
putStrLn "Type \"init\" to begin" >>
getLine >>= \l -> case l of
"init" -> act
_ -> main
act :: IO ()
act =
let score = foldM (
\acc (q,a) ->
putStrLn q >>
getLine >>= \l ->
if (l `elem` a)
then putStrLn "CORRECT!" >>
threadDelay (2 * 10^6) >>
acc >>= \a -> a + 1
else putStrLn "WRONG!" >>
threadDelay (2 * 10^6) >>
acc
) 0 qs
in putStrLn $ "Score: " ++ score >>
if (score > 18)
then putStrLn "Bravo!" >>
else putStrLn "Not enough!" >>
putStrLn "Type \"1\" to restart, anything else to quit" >>
getLine >> \l -> case l of
"1" -> act
_ -> exitSuccess
如果您自己提取迭代函数,则可以简化事情:
import Control.Monad
go score (question,answer) = do
putStr $ question ++ "? "
response <- getLine
if response /= answer
then do putStrLn "Wrong!"
return score
else do putStrLn "Right!"
return (score+1)
questions = [ ("1+1=", "2"), ("2+2","4"), ("What is your favorite color", "\n") ]
doit = foldM go 0 questions
import-Control.Monad
去得分(问题、答案)=去做
putStr$question++“?”
响应这里有一个示例,使用StateT
来同时考虑状态
和IO
module Main where
import Control.Monad.State
type Question = (String,String)
type Questions = [Question]
type Score = Int
type Game = StateT Score IO () -- combine State and IO effects
play :: Question -> Game
play (question,answer) = do
liftIO $ putStrLn question -- IO requires using the liftIO function explicitly
input <- liftIO $ getLine
if answer == input
then do
liftIO $ putStrLn "correct!"
modify (+1) -- add 1 to score
else
liftIO $ putStrLn "wrong!"
score <- get
liftIO $ putStrLn $ "Your score is: " ++ (show score)
questions :: Questions
questions = [("1+1=", "2"), ("What is the best programming language?", "haskell")]
main :: IO ()
main = do
runStateT (traverse play questions) 0 -- no need for foldM since we're using State to handle the score
putStrLn "game over"
modulemain其中
进口控制单体状态
类型问题=(字符串,字符串)
类型问题=[问题]
类型分数=整数
类型Game=StateT Score IO()--组合状态和IO效果
游戏:问题->游戏
玩(问题,回答)=做
liftIO$putStrLn问题——IO需要显式使用liftIO函数
如果没有IO,您可以使用状态进行输入。作为练习,您可以将所有代码转换为纯代码,例如,通过提供一个答案列表来替换交互式getLine。如果您想使用State和IO,您需要使用StateT(monad转换器:我建议您先编写纯版本)。
module Main where
import Control.Monad.State
type Question = (String,String)
type Questions = [Question]
type Score = Int
type Game = StateT Score IO () -- combine State and IO effects
play :: Question -> Game
play (question,answer) = do
liftIO $ putStrLn question -- IO requires using the liftIO function explicitly
input <- liftIO $ getLine
if answer == input
then do
liftIO $ putStrLn "correct!"
modify (+1) -- add 1 to score
else
liftIO $ putStrLn "wrong!"
score <- get
liftIO $ putStrLn $ "Your score is: " ++ (show score)
questions :: Questions
questions = [("1+1=", "2"), ("What is the best programming language?", "haskell")]
main :: IO ()
main = do
runStateT (traverse play questions) 0 -- no need for foldM since we're using State to handle the score
putStrLn "game over"