As @200_success mentions in a comment, this isn't a kosher use of
Ord. I believe though that it is the property of antisymmetry that is broken, not transitivity. \$Rock \leq Paper \leq Scissors \leq Rock\$ means that by transitivity \$Paper \leq Rock\$, which violates antisymmetry since \$Rock \neq Paper\$. This may seem academic, but many library functions will break or produce incoherent results given your instance. Try to guess what
sort [Rock, Scissors, Paper] will return. Don't get in the habit of writing bad instances just because you like their namespace.
What you should do instead is just write a grab bag of pure functions and domain-specific datatypes. This would look something like—
data Winner = PlayerOne | PlayerTwo | Tie
shoot :: RPS -> RPS -> Winner
shoot Rock Rock = Tie
shoot Rock Paper = PlayerTwo
shoot Rock Scissors = PlayerOne
All top-level definitions should have a type signature always, full stop.
main is always
main :: IO ().
Since you're not doing anything fancy with your
StdGen, just use the
main = do
humanchoice <- prompt "Rock, Paper, or Scissors: "
compchoice <- randomRIO (0,2)
One typeclass it would be appropriate to instance is
Random, so that you can have a more semantic computer-player interface. I'll toss in
Bounded instances because they make the
Random instance more future-proof.
data RPS = Rock | Paper | Scissors
deriving (Eq, Show, Read, Enum, Bounded)
instance Random RPS where
random g = randomR (minBound, maxBound) g
randomR (lo, hi) g = first toEnum $ randomR (fromEnum lo, fromEnum hi) g
where first f (a, b) = (f a, b)
The last thing I would do would be to factor out the result message code from
main, it's a little repetitive having
putStrLn there three times, and you can conceive of various scenarios like making this two player where you'd want to be able to easily swap around result message generators.
humanTwo :: Winner -> String
humanTwo PlayerOne = "You lose :("
humanTwo PlayerTwo = "You win! :)"
humanTwo Tie = "Tie."
And with all of those changes you end up with a
main function like—
main :: IO ()
main = do
humanchoice <- fmap read $ prompt "Rock, Paper or Scissors: "
compchoice <- randomIO
let winner = shoot compchoice humanchoice
putStrLn $ humanTwo winner