2013-03-18 25 views
14

GHCI似乎在交互式會話期間緩存函數的結果。很容易注意到,只需調用一個耗時的函數兩次。第二次,結果會立即出現。如何清除ghci的函數結果緩存?

有沒有辦法從GHCI中清除這個緩存,所以我不必重新啓動它?我正在做一些quick'n'drty非詳細的性能比較,所以使用System.CPUTime而不是矯枉過正。

+2

你可以舉一個具體函數調用的例子嗎? – dave4420 2013-03-18 18:13:55

+0

''讓f = 1:map(2 *)f''然後''last $ show $ f! 200000''。第一次,我的機器需要大約15秒,但是第二次立即計算。 – user42179 2013-03-18 18:30:34

+6

這不是一個函數。 – 2013-03-18 18:31:14

回答

4

正如註釋筆記,你使用let綁定到一個這是應用功能的結果。如果你想保持價值,不要將它命名爲let! (或者只是不參考已經在let中計算出的值)。

+0

這並不總是很簡單 - 例如,OP提供的示例是遞歸的,所以如果沒有'fix'就很難定義沒有'let' – amindfv 2013-03-18 19:52:16

+5

'let f = foo f'會給出一個綁定。 「讓f = foo f'不會。簡單! – sclv 2013-03-18 20:13:42

13

您可以隨時通過命令:r重新加載正在使用的模塊。這將丟棄您製作的任何交互式綁定,如果您只是在四處漫遊,這可能並不總是實用。如果你實際上沒有使用模塊,這也可以工作。

3

GHCI有+r選項,其中,according to the manual,應該做你想要什麼:

通常情況下,頂級表達任何評價中加載的模塊(也稱爲 CAF或常量應用型形式)是在評估之間保留 。打開+r會導致在每次評估後丟棄頂級 表達式的所有評估(它們在單次評估期間仍保留 )。

如果評估的頂級表達式爲 消耗大量空間,或者需要可重複的 性能測量,則此選項可能會有所幫助。

請注意,它談到constant applicative forms,而不是功能。但是,我不能讓它爲你工作,例如:

Prelude> :set +r 
Prelude> :set +s 
Prelude> let f = 1 : map (2*) f 
(0.01 secs, 1222216 bytes) 
Prelude> last $ show $ f !! 100000 
'6' 
(3.54 secs, 641914476 bytes) 
Prelude> last $ show $ f !! 100000 
'6' 
(0.04 secs, 1634552 bytes) 
Prelude> last $ show $ f !! 100000 
'6' 
(0.04 secs, 1603568 bytes) 

顯然,+r only works for compiled code,雖然文檔沒有提到這一點。

2

總之,

>>> :set +s -- activate performance 
>>> :r  -- reset all interactive binding 
Ok, modules loaded: none. 
>>> :show bindings -- check the binding state 

讓我們開始測試,

>>> let f = 1 : map (2*) f 
(0.01 secs, 1543272 bytes) 
>>> :show bindings 
f :: [Integer] = _ 
>>> last $ show $ f !! 50000 
'6' 
(0.55 secs, 170011128 bytes) 
>>> :show bindings 
f :: [Integer] = 1 : 2 : 4 : 8 : 16 : .... 
it :: Char = '6' 
>>> last $ show $ f !! 50000 
'6' 
(0.02 secs, 1562456 bytes) 

使用不確定,

>>> let f = undefined 
(0.01 secs, 565912 bytes) 
>>> :show bindings 
it :: Char = '6' 
f :: a = _ 
>>> let f = 1 : map (2*) f 
(0.01 secs, 513304 bytes) 
>>> last $ show $ f !! 50000 
'6' 
(0.94 secs, 170517840 bytes) 
>>> :show bindings 
f :: [Integer] = 1 : 2 : 4 : 8 : 16 : .... 
it :: Char = '6' 

重新綁定,

>>> :r 
>>> :show bindings 
Ok, modules loaded: none. 

另一個studie情況下,

>>> let h = (2*) 
(0.01 secs, 590232 bytes) 
>>> let f = 1 : map h f 
(0.01 secs, 1138792 bytes) 
>>> :show bindings 
it :: Char = '6' 
h :: Integer -> Integer = _ 
f :: [Integer] = _ 
>>> last $ show $ f !! 60000 
'6' 
(1.69 secs, 241802432 bytes) 
>>> last $ show $ f !! 60000 
'6' 
(0.03 secs, 2002432 bytes) 

仍緩存,改變H鍵查看結合,

>>> let h = (3*) 
(0.01 secs, 547208 bytes) 
>>> last $ show $ f !! 60000 
'6' 
(0.03 secs, 2029592 bytes) 
>>> :show bindings 
f :: [Integer] = 1 : 2 : 4 : 8 : 16 : .... 
h :: Integer -> Integer = _ 
it :: Char = '6' 

無論做,需要重新定義˚F也

>>> let f = 1 : map h f 
(0.01 secs, 552048 bytes) 
>>> last $ show $ f !! 60000 
'1' 
(4.36 secs, 374064760 bytes) 

使用讓...在...綁定,

>>> let f = let h = (2*) in 1 : map h f 
(0.02 secs, 1068272 bytes) 
>>> last $ show $ f !! 60000 
'6' 
(3.90 secs, 242190168 bytes) 
>>> last $ show $ f !! 60000 
'6' 
(4.89 secs, 242271560 bytes) 
>>> last $ show $ f !! 60000 
'6' 
(5.71 secs, 242196976 bytes) 
>>> :show bindings 
h :: Integer -> Integer = _ 
f :: Num a => [a] = _ 
it :: Char = '6'