Ric*_*ter 6 io haskell typechecking
我正在通过Haskell上的一些介绍性材料,并尝试完成此愚蠢的Rock,Paper和Scissors命令行实现。
我认为输入的类型防护足以使编译器确信输入是类型RPS,但是可惜不是。
如何告诉编译器输入数据是一种类型还是另一种类型?
data RPS = Rock | Paper | Scissors
_shoot :: RPS -> RPS -> String
_shoot Rock Paper = "Paper beats rock, you win!"
_shoot Paper Rock = "Paper beats rock, you loose."
_shoot Rock Scissors = "Rock beats scissors, you loose."
_shoot Scissors Rock = "Rock beats scissors, you win!"
_shoot Paper Scissors = "Scissors beats paper, you win!"
_shoot Scissors Paper = "Scissors beats paper, you loose!"
_shoot Rock Rock = "Tie!"
_shoot Scissors Scissors = "Tie!"
_shoot Paper Paper = "Tie!"
isRPS :: String -> Bool
isRPS s = elem s ["Rock", "Paper", "Scissors"]
main :: IO ()
main = do
putStrLn "Rock, Paper, or Scissors?"
choice <- getLine
if isRPS choice -- this was my idea but is apparently not good enough
then putStrLn (_shoot choice Rock)
-- ^^^^^^
-- Couldn't match type ‘[Char]’ with ‘RPS’ Expected type: RPS Actual type: String
else putStrLn "Invalid choice."
Run Code Online (Sandbox Code Playgroud)
Wil*_*sem 11
您没有将choice(是String)转换为RPS,甚至没有将a 转换为Maybe RPS:
readRPS :: String -> Maybe RPS
readRPS "rock" = Just Rock
readRPS "paper" = Just Paper
readRPS "scissors" = Just Scissors
readRPS _ = NothingRun Code Online (Sandbox Code Playgroud)
因此,在这里我们返回Just x给定的输入有效(带有x相应的RPS项),或者Nothing如果字符串不是有效的选项。
然后我们可以实现为:
import Data.Char(toLower)
main :: IO ()
main = do
putStrLn "Rock, Paper, or Scissors?"
choice <- getLine
case readRPS (map toLower choice) of
Just rps -> putStrLn (_shoot rps Rock)
Nothing -> putStrLn "Invalid choice."
mainRun Code Online (Sandbox Code Playgroud)
您就快到了,您只需要read函数即可将用户的字符串转换为RPS数据类型。
您需要做的第一件事是创建类型类RPS的实例Read。通过将data声明修改为:
data RPS = Rock | Paper | Scissors deriving Read
Run Code Online (Sandbox Code Playgroud)
什么deriving Read确实是给RPS了默认实例的Read类型类,这在明显的方式工作:read "Rock"将成为Rock等等,所提供的编译器知道你正在使用read在类型的值的情况下RPS,预计。
然后,您需要在main函数中做的就是更改此代码:
putStrLn (_shoot choice Rock)
Run Code Online (Sandbox Code Playgroud)
至
putStrLn (_shoot (read choice) Rock)
Run Code Online (Sandbox Code Playgroud)
由于_shoot有一个类型签名告诉GHC它的第一个参数必须是一个RPS值,因此它将知道使用read为RPS类型定义的instance实例,并且一切都会好起来的,因为您已经将有效的用户选择限制为这3个特定的字符串。
(请注意,对于较大的程序,有更安全,更好的方式来处理此类事情-请参阅Willem的答案中的一种简单方法-但这对于基本的学习练习是很好的。)
| 归档时间: |
|
| 查看次数: |
136 次 |
| 最近记录: |