我希望有一个函数读取任意int,直到插入数字'0',然后显示插入有序列表中的数字.
为此我写了这个函数:
import Data.List
readIntegers :: IO()
readIntegers = do
putStrLn "insert a number: "
num<-getLine
let list = ordList ((read num :: Int):list)
if (read num == 0)
then print list
else readIntegers
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
Run Code Online (Sandbox Code Playgroud)
这编译得很好,但是当我插入数字'0'时,它给了我这个错误:
*** Exception: <<loop>>
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么 ?
正如@phg指出的那样,你实际上是在构建一个无限列表,实际上对它进行评估会导致循环错误.解决此问题的一个简单实现是定义一个辅助函数,它接受一个额外的参数 - 一个列表来存储从屏幕读入的所有输入,如下所示:
readInteger :: IO ()
readInteger = readInteger' []
where
readInteger' x = do
putStrLn "insert a number: "
num<-getLine
if ((read num :: Int) == 0)
then print $ ordList x
else readInteger' $ (read num :: Int):x
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
Run Code Online (Sandbox Code Playgroud)
请注意,上面的内容基本上只是@phg答案的一个实现,但是对原始逻辑进行了一些更改.首先,由于0是一个标记值,我们不应该将它附加到我们的列表中.其次,我们不需要每次向其添加值时对列表进行排序.在打印/传递到另一个功能时排序一次就足够了.
如果你想在没有提示用户输入的情况下读取一个未指定数量的整数并在你遇到0时切断它,那么你可能会很好地使用getContents它,它将从标准输入读取所有内容作为单个字符串,懒洋洋地.
然后,将它解析为数字列表并使用它执行您想要的操作是一件简单的事情,如下所示:
readIntegers :: ()
readIntegers = do
a <- getContents
let b = ordList $ takeWhile (/= 0) $ map (\x -> read x :: Int) $ words a
mapM (putStrLn . show) b
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
Run Code Online (Sandbox Code Playgroud)