从输入Haskell读取数字

时间:2015-01-18 15:18:56

标签: haskell

我希望有一个函数读取任意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

这编译得很好,但是当我插入数字'0'时,它会给我这个错误:

*** Exception: <<loop>>

我做错了什么?

3 个答案:

答案 0 :(得分:7)

正如@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

请注意,上述内容基本上只是@ phg的答案的实现,但对原始逻辑进行了一些更改。首先,由于0是一个标记值,我们不应该将它附加到我们的列表中。其次,我们不需要每次向其添加值时对列表进行排序。在打印/传递到另一个功能时排序一次就足够了。

Demo

如果你想在没有提示用户输入的情况下读取未指定数量的整数并在遇到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 

答案 1 :(得分:4)

let list = ordList ((read num :: Int):list)

这基本上是[x, x, ...]形式列表的递归定义(就像你写了一个方程式x = 1 + x)。由于Haskell是懒惰的,所以这本身就很好。但是,如果你尝试print list(又名&#34;解决等式&#34;),它将会失败,因为它将尝试打印无限多个数字。

您可能对(:)运营商的运作存在误解。 Haskell函数永远不会执行赋值操作,并通过更改它num连接到list,就像在命令式语言中一样。只有函数。

如果你想累积所有数字,你应该尝试提出readIntegers的递归定义,将其状态(list)保存在一个附加参数中(还有更复杂的方法) ,隐藏状态传递,但对初学者使用更复杂)。

答案 2 :(得分:3)

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

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

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