getLine 是懒惰的吗?

Is getLine lazy?

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'

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

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)