2012-07-02 28 views

回答

6

你可能想要repeat其中的定義相當於你的第二個實現。

您的第一個示例中的[1,1..]表示法是enumFrom*前奏函數的語法糖。使用任何你喜歡的。

6

repeat/1:lst更好,他們不需要任何額外的計算,但[1,1..]作用:

[1,1..] = enumFromThen 1 1 = en 1 
      where en n = n : en (n + nΔ) 
        nΔ = 1-1 = 0 

所以它總是需要執行額外的1+0

3

要回答你的問題,兩者都展開,但letrepeat變體更好,因爲enumFrom變體經歷實際的枚舉,所以涉及無用的算術。

4

如果您不走運,您的第一個無限列表將使用無限量的內存。因此,使用你的第二個無限列表(或者,如果你更喜歡匿名無限列表,請使用Prelude中的repeat)。


示範。這樣做可能會讓watch free -m在另一個窗口中運行。

$ cat so.hs 
import Control.Exception (evaluate) 
import System.IO (hFlush, stdout) 

with :: String -> [Int] -> IO() 
with s xs 
    = do putStrLn $ "Summing part of a " ++ s 
     theSum <- evaluate $ sum (take 100000000 xs) 
     firstElem <- evaluate $ head xs 
     putStrLn $ "sum $ take 100000000 [" ++ show firstElem ++ "...] is " ++ show theSum 

main :: IO() 
main 
    = do with "call to repeat" (repeat 1) 
     putStr "Press return to continue..." 
     hFlush stdout 
     getLine 
     with "list comprehension" [1,1..] 

$ ghc -O --make so.hs 
[1 of 1] Compiling Main    (so.hs, so.o) 
Linking so ... 
$ ./so 
Summing part of a call to repeat 
sum $ take 100000000 [1...] is 100000000 
Press return to continue... 
Summing part of a list comprehension 
^C 

第一次總和運行在恆定的空間。第二個總和消耗了內存,所以在它導致我的筆記本電腦交換之前中斷它。

在這種簡單的情況下,我們可以在計算theSum之前通過計算firstElem來避免空間泄漏,但在現實世界的應用中,這可能是不可能的,或者至少難以追蹤。最好避免使用repeat

(關於優化的一個注意:如果我們不求和都在-O標誌傳遞給ghc然後sum意志內存泄露它不會是很難改寫sum = foldl' (+) 0,使其沒有空間泄漏,即使沒有-O我不知道導致目前實現的是什麼因素)

+0

你能詳細說明爲什麼第一個可能會使用無限的內存嗎? –

+2

我假設,因爲每個'1'可能實際上被分配並佔用幾個字節,而在第二種情況下,無論如何,只有一個'1'和一個指針。 – MatrixFrog

+0

@MatrixFrog正確。 – dave4420

相關問題