在自己的定义中使用的变量?

axi*_*sty 11 functional-programming scala lazy-evaluation delayed-execution

无限流:

val ones: Stream[Int] = Stream.cons(1, ones)

如何在自己的声明中使用值?看来这应该会产生编译错误,但它确实有效.

Chr*_*tin 9

看看Stream.cons.apply的签名:

apply[A](hd: A, tl: ? Stream[A]): Cons[A]

?对第二个参数表明它具有调用-名语义.因此,您的表达Stream.cons(1, ones)未经过严格评估; 在ones作为参数传递之前,不需要计算参数tl.


Arc*_*heg 9

它并不总是一个递归定义.这实际上有效并产生1:

val a : Int = a + 1
println(a)
Run Code Online (Sandbox Code Playgroud)

a键入时会创建变量val a: Int,因此您可以在定义中使用它.Int默认情况下初始化为0.一个类将为null.

正如@Chris指出的那样,Stream接受=> Stream[A]了一些其他规则,但我想解释一般情况.这个想法仍然是一样的,但变量是按名称传递的,所以这使得计算递归.鉴于它是通过名称传递的,它是懒惰地执行的.Stream逐个计算每个元素,因此ones每次需要下一个元素时都会调用它,从而导致同一个元素再次生成.这有效:

val ones: Stream[Int] = Stream.cons(1, ones)
println((ones take 10).toList) // List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
Run Code Online (Sandbox Code Playgroud)

虽然你可以无限流更容易:Stream.continually(1) 更新作为@SethTisue在评论中指出Stream.continuallyStream.cons是两个完全不同的方法,具有非常不同的结果,因为cons需要A的时候continually需要=>A的,这意味着continually在每次重新计算在内存中的元素,并将其存储,cons除非你把它转换成其他结构,否则可以避免存储n次List.continually只有在需要生成不同的值时才应使用.有关详细信息和示例,请参阅@SethTisue注释.

但请注意,您需要指定类型,与递归函数相同.

你可以使第一个例子递归:

lazy val b: Int = b + 1
println(b)
Run Code Online (Sandbox Code Playgroud)

这将stackoverflow.

  • 只需注意,`Stream.cons(1,ones)`是一个使用有限内存的循环结构,`Stream.continually(1)`是一个使用潜在无界内存的线性结构. (2认同)
  • 在仅使用几个字的内存的东西和可能消耗整个堆的东西之间存在巨大的实际差异.(但是,请注意,一旦你调用`take`,你最终会得到相同的结构,所以它是否重要取决于你对流实际做了什么.)进一步阅读:https://gist.github.com/ SethTisue/ce598578874accba98c0,https://groups.google.com/d/msg/scala-user/3yypUKJBP04/Q_bowgIry44J (2认同)
  • @SethTisue哇!我没有意识到`cons`需要`A`,当`连续'需要`=> A`时.我同意这使得这两种方法完全不同. (2认同)