2

有一种模式反复出现,我一直无法完全理解,例如下面的代码来计算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的元素。这不就像一个无限循环,一件事问另一件事,然后那件事又问自己。虽然代码工作完美。

4

1 回答 1

6

Scala 中的流是惰性求值的。这意味着只计算直到您实际需要的最后一个值的值。这对您的主要示例意味着什么:

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对于函数式程序员更直观。

于 2013-04-22T18:29:05.813 回答