In a Stackoverflow post about the creation of Fibonacci numbers I found the method #::
(What is the fastest way to write Fibonacci function in Scala?). In ScalaDocs I found this entry (see here, 1) describing the hash colon colon method as An extractor that allows to pattern match streams with #::.
I realized that I can use the fibonacci function like this
def fibonacci: Stream[Long] = {
def tail(h: Long, n: Long): Stream[Long] = h #:: tail(n, h + n)
tail(0, 1)
}
fibonacci(10) //res4: Long = 55
How should I understand the ScalaDocs explanation? Can you give an additional example?
Why it was not necessary to define a parameter in the fibonacci
function above?
In formal English, should can be used with I or we in conditional clauses, instead of the more common would. This form is usually, but not always, found together with an if clause. I should love to visit Peru if I had the money. I should be very cross if they didn't give me a certificate.
Luckily, using modal verbs in a sentence is pretty simple. For basic sentences—the simple present tense—just remember these rules: Modal verbs always come directly before the main verb (except for questions). With modal verbs, use the infinitive form of the main verb without “to”.
In your example h #:: tail(n, h + n)
creates a new stream, where the h
is the head of the stream and tail(n, h + n)
a stream which will be evaluated lazily.
Another (and maybe easier) example would be to define natural numbers as a stream of BigInt.
def naturalNumbers = {
def next(n: BigInt) : Stream[BigInt] = n #:: next(n + 1)
next(0)
}
println(naturalNumbers)
would result in printing Stream(0, ?)
, because the head is strict, meaning that it will be always evaluated. The tail would be next(1)
, which is only evaluated when needed.
In your example fibonacci(10)
is syntactic sugar for fibonacci.apply(10)
which is defined in the Stream
class and yields the element with the index in the stream.
You can also do a lot of others things with streams. For example get the first fibonacci number that is greater than 100: fibonacci.dropWhile(_ <= 100).head
or just print the first 100 fibonacci numbers println(fibonacci.take(100).toList)
The method #::
is defined for Streams. It is similar to the ::
method for Lists. The main difference between a List and a Stream is that the elements of a Stream are lazy evaluated.
There's some scala magic happens on the last line. Actually, first you're evaluating the fibonacci
expression, and it returns a Stream
object. The first and the second elements of this stream are 0 and 1, as follows from the third line of your example, and the rest of the Stream is defined via recursive call. And then you're extracting tenth element from the stream, and it evaluates to 55.
In the code below, I show similar access to the fourth List's element
val list = List(1,2,3,4,5)
println(list(3)) // prints 4
In a nutshell, think about Streams as infinite Lists. You can find more about Streams here http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Stream
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With