在Haskell中验证正整数列表

l5tcr1uw  于 2023-01-13  发布在  其他
关注(0)|答案(1)|浏览(136)

我想写一个Haskell程序,从标准输入中读取一个正整数列表,如果用户写了一个不同的东西,如一个负数列表,一个字符列表或一个不是列表的东西,程序需要通知用户并从标准输入中再次读取,直到用户写了一个正确的列表。这是我写的,但如果用户键入一个包含字符的列表,或者一个单个数字/字符而没有用方括号把它括起来,程序结束。相反,如果用户键入一个包含负数的列表,或者空列表,程序工作得很好。谢谢你的建议。

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
06odsfpq

06odsfpq1#

首先,让我们看看您的解决方案及其错误所在。错误会用注解标记。

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

现在,我们知道了您的实现中存在的问题,让我们来解决它

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)

出于完整性的考虑,最后一个模式匹配可以使用guard来简化,但这不是已知的语法

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

相关问题