是getLine
懶惰?是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'和''getLine''都是同樣嚴格的。 IO操作不能懶惰地返回,除非通過利用一些'unsafe'函數 - 這被稱爲「惰性IO」,並且必須小心處理,因爲實際的讀取會由於懶惰而在後面開始,這可能會導致一些問題。惰性IO是(很)很難調試的。但是,您可以使用嚴格的自定義'get3Ints',它只能讀取所需字符串的一部分。 – chi
'getLine'必須嚴格才能正確,正如chi所說,你的'getLine''表現完全一樣。如果'getLine'不是嚴格的,那麼你稍後做的純計算會通過實現懶惰輸入中的更多字符而導致IO。當你考慮其他的IO也可能會發生時,這將是一場噩夢,也從標準輸入讀取:哪些字符去哪裏將是非常難以弄清楚。 – amalloy
參考[這個回答](https://codereview.stackexchange.com/a/120037/16551)看到更多關於'IO'和懶惰的信息。如果你想要一個懶惰的'getLine',它可能需要一個類似於'IO(ListT IO Char)'的類型,其中'data ListT m a = Nil |缺點(m(ListT m a))'(如果您以給定長度的塊讀取輸入以提高效率,您也可以使用'ListT IO String'而不是'ListT IO Char'。 – gallais