从输入Haskell读取数字

从输入Haskell读取数字,haskell,Haskell,我想要一个函数,它读取任意整数,直到插入数字“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 pr

我想要一个函数,它读取任意整数,直到插入数字“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
导入数据。列表
readIntegers::IO()
readIntegers=do
putStrLn“插入一个数字:”
num[Int]
订单列表[]=[]
ordList xs=排序xs
这可以很好地编译,但当我插入数字“0”时,会出现以下错误:

*** Exception: <<loop>>
***例外情况:
我做错了什么

let list = ordList ((read num :: Int):list)
这基本上是一个递归的列表定义,其形式为
[x,x,…]
(就像你写了一个等式,表示
x=1+x
)。这本身就很好,因为哈斯克尔很懒;但是,如果您尝试打印列表(也称为“解方程”),它将失败,因为它将尝试打印无限多个数字

您可能对
(:)
运算符的工作方式有误解。Haskell函数永远不会执行赋值操作,也不会通过更改将
num
连接到
list
上,就像在命令式语言中一样。只有纯函数


如果你想累加所有的数字,你应该尝试给出一个递归的
readIntegers
,把它的状态(列表)保存在一个额外的参数中(还有更复杂的方法,隐藏状态传递,但是对于初学者来说使用起来更复杂)

正如@phg所指出的,您实际上是在构造一个无限列表,而实际计算它会导致循环错误。解决此问题的一个简单实现是定义一个helper函数,该函数使用一个附加参数—一个列表来存储从屏幕读取的所有输入,如下所示:

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

对于更复杂的解决方案,请注意这是一个展开,您可以使用Control.Monad.Loops中的
unfolm
来实现它:

import Control.Monad.Loops (unfoldM)

readInts :: IO [Int]
readInts = unfoldM $ fmap (check . read) getLine
  where check x = if x == 0 then Nothing else Just x

它有一个很好的属性,即它按照读取列表的顺序返回列表。

实际上,
list
本身已经在发散,因为
ordList
对脊椎是严格的。这是一个非常好的解决方案。