getLine懒惰吗?

时间:2017-08-20 21:36:31

标签: haskell io lazy-evaluation processing-efficiency

getLine懒惰吗?

说我在输入上有很长的一行。它只是一系列数字。我只需要加上3个第一个数字。 getLine是否有效并且只读取该行的第一部分,或者我是否必须创建自己的惰性行读取函数,这将逐个读取字符?

如果我要对整条线求和,我的实施是否有效? (由于逐个读取字符会产生开销吗?)

import Control.Applicative

main = do
    line <- getLine'
    print $ sum $ map read $ take 3 $ words line

getLine' :: IO String
getLine' = do
    c <- getChar
    if c == '\n' then return [] else (c:) <$> getLine'

1 个答案:

答案 0 :(得分:1)

虽然getLine不是懒惰,getContents是,但它可以与lineswords等功能结合使用。因此,以下程序只会读取足够的stdin来从第一行获取(最多)三个整数并打印它们的总和:

main :: IO ()
main = do contents <- getContents
          let lns = lines contents
              result = sum $ map read $ take 3 $ words $ head lns
          print (result :: Integer)

请注意,如果您修改程序以访问后续行 - 例如,如果您添加了:

putStrLn $ take 80 $ lns !! 1

到程序的底部打印第二行的前80个字符,然后程序必须完成读取第一行(因此会在程序的最后两行之间稍微挂起)第二个的前80个字符。换句话说,只有当需要读取第一行的第一位时,这个懒惰的行读取才有用,如果这对您来说不是很明显 - Haskell不会这样做有任何神奇的方法可以跳过第一行的其余部分到达第二行。

最后,请注意,对于上述程序,如果第一行上的整数少于三个,那么它只是将这些数字相加并且不会尝试读取第一行(我是认为是你想要的)。如果您实际上并不关心行结尾,只想对文件中的前三个数字求和,无论它们如何划分为行,那么您可以将内容直接分解为像这样:

main = do contents <- getContents
          let result = sum $ map read $ take 3 $ words contents
          print (result :: Integer)