2012-05-04 20 views
6

我目前正在通过“Scala编程”书籍学习Scala。到目前为止,已经有一切看起来怪异的(从Java程序员的角度来看)很好的解释,但使用流生成斐波那契序列是其中一个例子让我有种困惑:Stream-cons#::如何在Scala中翻译?

def fibFrom(a: Int, b: Int): Stream[Int] = 
    a #:: fibFrom(b, a + b) 

如何建设流的完成?当然,#::运营商对此负有责任。我明白,因为它在:结束,它是正确关联,但这并不解释流的创建。我猜它是以某种方式隐式转换为构造函数,但我不明白为什么以及如何。

我已经在Predef.scalaLowPriorityImplicits.scala寻找答案,但到目前为止还没有运气。

任何人都可以启发我吗?

回答

8

这是正确的关联,因此可以作为右边参数的方法:

fibFrom(b, a + b).#::(a) 

至少这是它试图语法做。 Stream[Int]没有这样的方法。幸运的是,object Stream已隐含到一些类ConsWrapper它有这种方法(code)。

所以,你以后隐式解析,得到的是这样的:

immutable.this.Stream.consWrapper(fibFrom(b, a + b)).#::(a) 
+0

谢谢,就是这样。我忘记了隐式转换也可以在应该转换的类的伴随对象中定义。 – rolve

+5

Scaladoc应该可能会自动包含那些硬编码的伴随含义。 – Debilski

+2

也许向其他人指出,Scala并不认为它是正确联合的。这也是ConsWrapper将'#::'实现为[call-by-name](https://github.com/scala/scala/blob/v2.10.3/src/library/scala/collection/immutable/Stream。斯卡拉#L1042)。即'ConsWrapper(tl:⇒Stream [A])'中的'⇒',以便翻译成'immutable.this.Stream.consWrapper(fibFrom(b,a + b))。#::(a)'表示'fibFrom(b,a + b)'只会在访问时被调用。 – nicerobot

2

流是类似于列表。它只知道它的头部和流的其余部分:流(头:T,尾:流[T])。不同之处在于,流是懒惰评估的。该方法名称末尾的':'表示该方法是正确的关联。因此,编译器(编译器)将#:: fibFrom(b,a + b)表达式转换为fibFrom(b,a + b)。#::(a)。

+0

谢谢,这正是我所想的,但并未解释如何创建Stream对象。如果Stream有一个方法'#::',这会导致无限递归我猜。 – rolve

+0

#::与列表中的::相同。是的,这是一个无限的递归。你只需要你想要的元素数量。这正是我想通过对它进行懒惰评估而表达的想法。这意味着只有在需要计算时才会计算它。 –

+0

这不完全相同,没有。如果它是相同的,那么你将在那里有一个无限递归。相反,'#::'(在'ConsWrapper'类中定义,而不是Stream!)有一个延迟评估的by-name参数。 – rolve