I made this Rock Paper Scissors game and I would like for this to be critiqued.import System.IOimport System.Randomimport Control.Monadimport Control.Arrowdata Throw = Rock | Paper | Scissors           deriving (Show, Read, Enum, Bounded)instance Random Throw where  random g = first toEnum $ randomR (a, b) g    where a = fromEnum (minBound :: Throw)          b = fromEnum (maxBound :: Throw)  randomR (a, b) g = first toEnum $ randomR (a', b') g    where a' = fromEnum a          b' = fromEnum bbeats :: Throw -> Throw -> BoolRock     `beats` Scissors = TruePaper    `beats` Rock     = TrueScissors `beats` Paper    = True_        `beats` _        = Falseplay :: Throw -> Throw -> Stringplay p1 p2  | p1 `beats` p2 = You win!  | p2 `beats` p1 = You lose.  | otherwise     = Tie.main :: IO ()main = do  putStr Enter your move [Rock, Paper, or Scissors]:   hFlush stdout  p1 <- getLine >>= readIO  p2 <- liftM (fst . random) getStdGen  putStrLn $ show p1 ++  vs.  ++ show p2  putStrLn $ play p1 p2
First attempt at writing Rock Paper Scissors game
game;haskell;rock paper scissors
The style is pretty good, I can just see two minor improvements you could do: Firstly, you can define random in terms of your own randomR in order to save a few keystrokes:instance Random Throw where  random = randomR (minBound, maxBound)  randomR (a, b) g = ...At this point Haskell's typing even derives the type of minBound for you, so you can lose the explicit annotations.Second, you should probably use randomIO instead of liftM (fst . random) getStdGen. That is not only shorter, but also updates the generator state, which means that you won't get the same result if you call it twice in the program.