2

fib 是否从一开始就对 cumfib 的每个元素进行评估?

fib = (1:1: zipWith (+) fib (tail fib))
cumfib = [ sum $ take i fib | i<-[1..]]

还是前 i 个元素被缓存并重用于 cumsum 的元素 (i+1)?

我或多或少猜测 fib 用于同一个 lambda 表达式,因此 is 只计算一次。

此外,fib 的实施是否与评估第 i 个斐波那契数的频率有关?我的实际问题涉及素数而不是斐波那契数,我希望将其“缓存”以轻松评估某个数 n 的素数。但是,我只使用

takeWhile (\x-> x*x<n) primes 

的素数。由于我先评估小 n 的因子,然后再评估大 n 的因子,因此这个素数子集会增加,因此我想知道,如果我这样做,素数的评估频率是多少:

primes = ... some way of calculating primes ...
helpHandlePrimes ... = ... using primes ...
handlePrimes = ... using primes and helpHandlePrimes ...

请让我知道 primes 是否评估一次,多次,或者这是否无法从我提出问题的方式来确定。

4

2 回答 2

5

let-bound 术语通常在其范围内共享。特别是,模块中的顶级术语在整个程序中共享。但是,您必须注意术语的类型。如果该术语是一个函数,那么共享意味着仅共享 lambda 抽象,因此不会记忆该函数。重载项在内部表示为函数,因此共享对于重载项也毫无意义。

所以如果你有一个单态的数字列表,那么它将被共享。默认情况下,fib您给出的列表将是单态的,因为“单态限制”(实际上这是一个有用的情况)。然而,这些天来禁用单态限制是一种时尚,所以无论如何我建议给出明确的类型签名,例如

fib :: [Integer]

确保并向所有人明确说明您希望这是一个单态列表。

于 2014-03-13T09:50:37.417 回答
0

我想以这种方式补充一点,不必要cumfib地重新计算. 它可以更有效地定义为ifib

cumfib = tail $ scanl (+) 0 fib
于 2014-03-13T18:39:07.117 回答