I'm making my way through some introductory material on Haskell and trying to complete this silly Rock, Paper, Scissors implementation for the command line.
I would think that a type guard on the input would be good enough to convince the compiler that the input is of the type RPS
, but alas, it is not.
How does one go about telling the compiler that input data is of one type or another?
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."
You did not transform the choice
(which is a String
) to an RPS
, or even better a Maybe RPS
:
readRPS :: String -> Maybe RPS
readRPS "rock" = Just Rock
readRPS "paper" = Just Paper
readRPS "scissors" = Just Scissors
readRPS _ = Nothing
Here we thus return a Just x
given the input is valid (with x
the corresponding RPS
item), or Nothing
if the string is not a valid option.
We can then implement this as:
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."
main