Search code examples
haskellioconditional-statementsgetline

Converting user input (Integer) to conditional print statements


I am trying to get a numeric value from the user (ranging 1-10) and using conditional statements (if number >= 1 && <=3) print out health status (e.g. putStrLn "your health is poor") but getting error message that I can't go past

health :: IO ()
health = do 
        putStrLn "State your health using numbers 1 - 10: "
        num <- getLine
        --putStrLn "Your health is: "
        if num >=1 && <=3
              then 
               do putStrLn "Your health is poor"
           else if num >=4 && getLine <=7
              then putStrLn "Your health is OK"
           else if num >=8 && getLine<=10
              then putStrLn "your health is fanstastic"
              else "Wrong health range indicated"

Error message:

healthCheck.hs:9:1: warning: [-Wtabs]
Tab character found here, and in five further locations.
Please use spaces instead.
|
9 |                         --putStrLn "Your health is: "   | ^^^^^^^^

healthCheck.hs:10:39: error: parse error on input ‘<=’
|
10 |                         if num >=1 && <=3    |

Solution

  • You make some mistakes here, mainly with the types:

    The line:

    num <- getLine
    

    means that num is a String, but you later use it as a number. You probably want to use readLn :: Read a => IO a, and probably it is better to specify the type as well:

    num <- readLn :: IO Int

    In your first if cases:

    if num >=1 && <=3
    

    Is wrong since it is parsed as (num >= 1) && (<= 3). The right operator is thus not a Bool, but an (Num n, Ord n) => n -> Bool, so a function. A function is not True or False.

    You should replace it with:

    if num >=1 && num <=3

    Later you write:

    if num >=4 && getLine <=7

    but here again the types do not match: getLine has type IO String, so it is not a number, it is even not an IO Int. You probably want to reuse the num, so:

    if num >=4 && num <=7

    Finally in the else stament, you write:

    else "Wrong health range indicated"

    But the type of health is IO (), not String, you thus should use putStrLn:

    else putStrLn "Wrong health range indicated"

    You can factor the putStrLn out, into:

    health :: IO ()
    health = do 
        putStrLn "State your health using numbers 1 - 10: "
        num <- readLn :: IO Int
        --putStrLn "Your health is: "
        putStrLn $
            if num <= 0 || num > 10 then "Wrong health range indicated"
            else if num <= 3 then "Your health is poor"
            else if num <= 7 then "Your health is OK"
            else "your health is fanstastic"

    The above is still not ideal, since reading a string into an Int can go wrong. So it might help to use readMaybe here to make the program safer.