Alb*_*zon 1 io haskell functional-programming
嗨,我有一个非常noob的问题,让我说我想创建一个游戏,当你必须回答问题时,我写了这个
data Question = Question { answer::String, text::String }
data Player = Player { name::String, points::String }
answerQuestion :: Question -> Player -> Player
answerQuestion question player
| isCorrect question playerAnswer = Player (name player) (points player + 1)
| otherwise = player
where
playerAnswer = do
putStrLn text(question)
getLine
isCorrect :: Question -> String -> Bool
isCorrect question try = try == answer(question)
Run Code Online (Sandbox Code Playgroud)
现在playerAnswer有类型IO String所以我必须isCorrect在do块内调用吗?有另一种方式来解析IO String成String?
在第一种情况下,我感觉失去了函数式编程的所有好处,因为我最终会在do块中编写我的整个代码以便访问String值
注意:这篇文章是用文字Haskell编写的.您可以将其保存为Game.lhs并在GHCi中尝试.
现在playerAnswer有类型
IO String所以我必须在do块内调用isCorrect吗?
是的,如果你坚持这个课程.
有另一种方式来解析
IO String成String?
没有,这不是不安全的.一个IO String东西可以给你一个String,但无论用什么String用来留下来IO.
在第一种情况下,我感觉失去了函数式编程的所有好处,因为我最终会在do块中编写我的整个代码以便访问String值.
如果您不提前进行测量,可能会发生这种情况.但是,让我们从自上而下的方法来解决这个问题.首先,让我们介绍一些类型别名,以便我们清楚地看到一个Stringin作为答案或名称:
> type Text = String
> type Answer = String
> type Name = String
> type Points = Int -- points are usually integers
Run Code Online (Sandbox Code Playgroud)
您的原始类型保持不变:
> data Question = Question { answer :: Answer
> , text :: Text } deriving Show
> data Player = Player { name :: Name
> , points :: Points } deriving Show
Run Code Online (Sandbox Code Playgroud)
现在让我们考虑一下游戏.你想问问玩家一个问题,得到他的答案,如果他是对的,加上一些观点:
> gameTurn :: Question -> Player -> IO Player
> gameTurn q p = do
> askQuestion q
> a <- getAnswer
> increasePointsIfCorrect q p a
Run Code Online (Sandbox Code Playgroud)
这足以让你在一个回合中填满你的游戏.让我们用生活来填补这些功能.askQuestions并getAnswer改变世界:他们在终端上打印一些东西并要求用户输入.他们必须要在IO一些点:
> askQuestion :: Question -> IO ()
> askQuestion q = putStrLn (text q)
> getAnswer :: IO String
> getAnswer = getLine
Run Code Online (Sandbox Code Playgroud)
在我们实际定义之前increasePointsIfCorrect,让我们再考虑一个不再使用的版本IO:
> increasePointsIfCorrect' :: Question -> Player -> Answer -> Player
> increasePointsIfCorrect' q p a =
> if isCorrect q a
> then increasePoints p
> else p
Run Code Online (Sandbox Code Playgroud)
顺便说一句,如果你仔细观察,你会注意到这increasePointsIfCorrect'实际上只是一场比赛.毕竟,它会检查答案并增加积分.说起:
> increasePoints :: Player -> Player
> increasePoints (Player n p) = Player n (p + 1)
> isCorrect :: Question -> Answer -> Bool
> isCorrect q a = answer q == a
Run Code Online (Sandbox Code Playgroud)
我们现在定义了几个不使用的函数IO.所有缺少的是increasePointsIfCorrect:
> increasePointsIfCorrect :: Question -> Player -> Answer -> IO Player
> increasePointsIfCorrect q p a = return (increasePointsIfCorrect' q p a)
Run Code Online (Sandbox Code Playgroud)
您现在可以通过一个简单的短游戏来检查:
> theQuestion = Question { text = "What is your favourite programming language?"
> , answer = "Haskell (soon)"}
> thePlayer = Player { name = "Alberto Pellizzon"
> , points = 306 }
>
> main :: IO ()
> main = gameTurn theQuestion thePlayer >>= print
Run Code Online (Sandbox Code Playgroud)
还有其他方法可以解决这个问题,但我想这对初学者来说更容易.
无论哪种方式,最好的是我们现在可以在不使用的情况下测试所有逻辑IO.例如:
prop_increasesPointsOnCorrectAnswer q p =
increasePointsIfCorrect' q p (answer q) === increasePoints p
prop_doesnChangePointsOnWrongAnswer q p a = a /= answer q ==>
increasePointsIfCorrect' q p a === p
ghci> quickCheck prop_increasesPointsOnCorrectAnswer
OK. Passed 100 tests.
ghci> quickCheck prop_doesnChangePointsOnWrongAnswer
OK. Passed 100 tests.
Run Code Online (Sandbox Code Playgroud)
完全实现这些测试超出了这个问题的范围.
playGame :: [Question] -> Player -> IO (),接下来问几个问题并告诉玩家最终得分.