【问题标题】:Understanding Streams了解流
【发布时间】:2013-04-15 18:02:00
【问题描述】:

有一种模式反复出现我一直没能完全理解,比如下面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

我不明白的是:filter 中的primes 使用isPrime。但是def isPrime 再次使用相同的primes 来获取元素。这不就像一个无限循环,一件事问另一件事,然后那件事又问自己。尽管代码运行良好。

【问题讨论】:

标签: scala


【解决方案1】:

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-07-23
    • 2016-07-04
    • 1970-01-01
    • 2023-04-04
    • 2018-03-19
    • 2015-04-29
    • 2016-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多