从输入Haskell读取数字
我想要一个函数,它读取任意整数,直到插入数字“0”,然后将插入的数字显示在有序列表中 为此,我编写了以下函数:从输入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
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
对脊椎是严格的。这是一个非常好的解决方案。