Guard inside 'do' block - haskell

A do expression [Haskell-report] only consists out of exp, pat <- exp, and let … statements, and the compiler will desugar these. Hence without some language extensions, you can not write guards in a do block. Furthermore it is likely not a good idea to enable that anyway. What if you for example would want to use two "guard blocks" next to each other? Then the two would "merge" and thus the guards of the first block would already eleminate (nearly) all cases.

You can use another let clause here:

game :: IO ()
game 0 = return ()
game n = do
    putStrLn "guess number: 0-99"
    number <- getLine
    let y = read number
    let x = 20
    let action | y > x = putStrLn "your number is greater than x" >> game (n-1)
               | y < x = putStrLn "your number is less than x" >> game (n-1)
               | otherwise = putStrLn "U win!!"
    action

Note that the otherwise in the original question will never get triggered, since a value is less than, greater than, or equal to another value.


Lots of problems there.

First, you can't say game = something and game n = something, so remove the game = return () line. (You may have been trying to write a type signature, but that's not one.)

Second, you can't drop into guard syntax in arbitrary places. The closest valid thing to what you wrote are multi-way if-expressions, which would let you write this:

{-# LANGUAGE MultiWayIf #-}
game n = do putStrLn "guess number: 0-99"
            number<-getLine
            let y = read number
            let x =20
            if
              | y>x -> putStrLn "your number is greater than x"
              | y<x -> putStrLn "your number is less than x"
              | y==x-> putStrLn "U win!!"
              | otherwise -> game (n-1)

Third, the Ord typeclass is supposed to be for types with a total order, so unless you're using unlawful things like NaN, you'll always have one of y>x, y<x, or y==x, so the otherwise will never be entered.

Fourth, comparing with <, ==, and > is unidiomatic and slow, since it has to keep repeating the comparison. Instead of doing that, do something like this:

case y `compare` x of
  GT -> _
  LT -> _
  EQ -> _

You could also just use case or LambdaCase.

{-# LANGUAGE LambdaCase #-}

game  :: Int -> IO ()
game n = case n of
  0 -> putStrLn "used all attempts"
  n -> 
    putStrLn "guess a number: 0 - 99" >>
    (`compare` 20) . read <$> getLine >>= 
      \case 
        EQ -> putStrLn "U win"
        GT -> putStrLn "your number is greater than x" >> 
              game (n - 1)
        LT -> putStrLn "your number is less than x" >> 
              game (n - 1)