2013-04-22 47 views
2

还有就是重新出现一次又一次的一个模式,我一直没能完全理解它,例如下面的code计算isPrime理解流

class S99Int(val start: Int) { 
    import S99Int._ 
    def isPrime: Boolean = 
    (start > 1) && (primes takeWhile (_ <= Math.sqrt(start)) forall (start % _ != 0)) 
} 

object S99Int { 
    implicit def int2S99Int(i: Int): S99Int = new S99Int(i) 
    val primes = Stream.cons(2, Stream.from(3, 2) filter { _.isPrime }) 
} 
import S99Int._ 

24 isPrime  //returns false 

什么我不明白的是:在primesfilter使用isPrime。但是def isPrime也使用相同的primes来取元素。难道它不像一个事物问一个问题,然后又是一个单一问题的无限循环。尽管代码完美无缺。

+2

有关类似问题,请参阅http://stackoverflow.com/questions/15594227/calculating-prime-numbers-in-scala-how-does-this-code-work。 – sschaef 2013-04-22 19:30:52

回答

6

斯卡拉流是懒惰评估。这意味着只有实际需要的最后一个值被计算出来。这是什么意思为您最好的例子:

isPrime不使用整个primes流,但只有部分的它:

(primes takeWhile (_ <= Math.sqrt(start)) 

它使用的是只有部分比平方根小你想测试的数量(和下一个,因为你必须评估它,看看它是否太大)。当现在primes再次为isPrime这些较小号码之一时,primes所需的部分更小。这继续,直到达到它的初始2.

觉得作为一个相互递归函数:

  • isPrime为是
  • primes可被视为primesUpTo(n: Int)

然后:

class S99Int(val start: Int) { 
    import S99Int._ 
    def isPrime: Boolean = 
    (start > 1) && (S99Int.primesUpTo(math.sqrt(start).toInt) forall (start % _ != 0)) 
} 

object S99Int { 
    implicit def int2S99Int(i: Int): S99Int = new S99Int(i) 
    def primesUpTo(n: Int): IndexedSeq[Int] = { 
    if (n >= 2) 2 +: (3 to n) filter { _.isPrime } 
    else IndexedSeq.empty 
    } 
} 

Stream为您实现的唯一一件事是缓存primesUpTo(n: Int)中的值,以便它们仅计算一次,并使功能程序员的表达式UpTo更直观。