getLine
是懒惰的吗?
假设我有一个非常长的输入行,它只是一系列数字。我只需要计算前三个数字的总和。 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
和你的getLine'
都同样严格。IO操作不能返回惰性,除非利用一些unsafe
函数--这被称为“lazy IO”,必须小心处理,因为由于惰性,实际读取将稍后开始,这可能会导致一些问题。懒惰IO是(臭名昭著的)难以调试的。但是,您可以使用一个严格的自定义get3Ints
,它仅读取您需要的字符串部分。 - chigetLine
必须是严格的,正如Chi所说,你的getLine'
行为完全相同。如果getLine
不是严格的,则稍后进行的纯计算将导致IO,通过从惰性输入中实现更多字符。当你考虑到其他IO也可以在进行中,也从标准输入读取时,这将是一场噩梦:哪些字符会被放置在何处将非常难以确定。 - amalloyIO
和惰性的更多信息。如果你想要一个惰性的getLine
,它可能需要一个类似于IO (ListT IO Char)
的类型,其中data ListT m a = Nil | Cons a (m (ListT m a))
(如果你按给定长度的块读取输入以提高效率,也可以使用ListT IO String
代替ListT IO Char
)。 - gallais