17

GHCI 似乎在交互式会话期间缓存函数的结果。很容易注意到,只需调用两次耗时的函数。第二次,结果将立即出现。

有没有办法从 GHCI 中清除这个缓存,所以我不必重新启动它?我正在做一些快速'n'dirty非详细的性能比较,所以使用 System.CPUTime 来代替会是矫枉过正。

4

5 回答 5

14

您始终可以通过命令重新加载您正在使用的模块:r。这将丢弃您所做的任何交互式绑定,如果您只是四处寻找,这可能并不总是实用的。如果您实际上没有使用模块,这也适用。

于 2013-03-18T20:39:14.767 回答
6

正如评论所指出的,您用于将名称let绑定到一个,该值是应用函数的结果。如果您想保留该值,请不要在 let 中命名它!(或者只是不要引用您已经在 let 中计算的值)。

于 2013-03-18T19:15:38.190 回答
4

GHCi 有一个+r选项,根据手册,它应该做你想做的事:

通常,加载模块中顶级表达式(也称为 CAF 或常量应用形式)的任何求值都会在求值之间保留。打开+r会导致在每次评估后丢弃对顶级表达式的所有评估(在单次评估期间仍会保留它们)。

如果评估的顶级表达式占用大量空间,或者您需要可重复的性能测量,此选项可能会有所帮助。

请注意,它讨论的是常量应用形式,而不是函数。但是,我无法让它适用于您的示例:

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仅适用于已编译代码,尽管文档没有提及这一点。

于 2013-03-20T22:33:28.220 回答
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.

另一个研究案例,

>>> 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 .. in ... 绑定,

>>> 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'
于 2013-03-21T01:23:28.553 回答
0

2019 年的答案:不可能……

于 2019-10-29T00:24:55.970 回答