Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Validate a list of positive integer numbers in Haskell

I want to write an Haskell program that read a list of integer positive numbers from stdin, if user write a different thing like a list of negative numbers, a list of characters or a thing that isn’t a list, program need to advise user and read again from stdin until user write a correct list.
This is what I wrote but if user type a list that contain a char, or a single single digit/char without close it in square brackets, program ends.
Instead if user type a list containing negative numbers, or empty list, program works well.
Thanks in advice.

main :: IO()
main = do  
  putStrLn "\nType a list of positive integers enclosed in square brackets and separated by commas:"
  list <- readIntList
  putStrLn "\nList:"
  print list

readIntList :: IO [Double]
readIntList = do
  readedList <- getLine
  let list = read readedList
  case checkList list && not (null list) of
    True -> return list
    False -> putStrLn "\nInvalid input, type again:" >> readIntList

checkList :: [Double] -> Bool
checkList = all checkNumber

checkNumber :: (Ord a, Num a) => a -> Bool
checkNumber n
  | n > 0 = True
  | otherwise = False

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

First, let’s take a look to your solution and what’s wrong with it. Errors are marked with a comment.

main :: IO()
main = do  
  putStrLn "\nType a list of positive integers enclosed in square brackets and separated by commas:"
  list <- readIntList
  putStrLn "\nList:"
  print list

readIntList :: IO [Double]
readIntList = do
  readedList <- getLine
  -- This will fail!! at run time. read function expect wellform input, 
  -- Therefore, you can't control the errors this way
  let list = read readedList
  -- This is kind of right, but it could be done better by pattern matching
  case checkList list && not (null list) of
    True -> return list
    False -> putStrLn "\nInvalid input, type again:" >> readIntList

-- These two can be simplify into one. See below
checkList :: [Double] -> Bool
checkList = all checkNumber

checkNumber :: (Ord a, Num a) => a -> Bool
checkNumber n
  | n > 0 = True
  | otherwise = False

Now, we know what’s wrong with your implementation. Let’s fix it

import Text.Read

main :: IO()
main = do  
  putStrLn "\nType a list of positive integers enclosed in square brackets and separated by commas:"
  list <- readIntList
  putStrLn "\nList:"
  print list

readIntList :: IO [Double]
readIntList = do
  readedList <- getLine
  -- use readMaybe from Text.Read module. It returns Nothing if the input is badform
  -- returns, Just xs otherwise
  case readMaybe readedList of
    Nothing -> do
      -- This is the case when input isn't a list of numbers
      putStrLn "Invalid Input type. Try again:\n"
      readIntList
    Just [] -> do
      -- This is the case of an empty list input.
      putStrLn "Input must be not empty. Try again:\n"
      readIntList
    Just xs ->
      -- This is the case input is a nonempty list of numbers, but we don't know if positive
      --  hence we must check all positive numbers.
      if checkList xs
        then pure xs
        else do 
          putStrLn "all input numbers must be positive. Try again:\n" 
          readIntList

-- Checking all positives numbers is as simple as this one.
checkList :: [Double] -> Bool
checkList = all (>0)

For the sake of completeness, the last pattern match can be simplify using guards, but it isn’t that known syntax

  case readMaybe readedList of
    --  ... other patterns as before 
    Just xs 
      | checkList xs -> pure xs
      | otherwise ->  do 
          putStrLn "all input numbers must be positive. Try again:\n" 
          readIntList
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading