Lindon Lindon - 1 year ago 55
Scala Question

First Element of a Lazy Stream in Scala

Here is a minimal example, I can define a function that gives my the next integer via

def nextInteger(input: Int): Int = input+1

I can then define a lazy stream of integers as

lazy val integers: Stream[Int] = 1 #:: integers map(x=>nextInteger(x))

To my surprise, taking the first element of this stream is 2 and not 1

scala> integers
res21: Stream[Int] = Stream(2, ?)

In this simple example I can achieve my desired result using 0 instead of 1 in the definition of integers, but how can one in general set up a stream such that the initial value isn't lost? In my case I am setting up an iterative algorithm and will want to know the initial value.

Furthermore, I've never understood the design choice which makes the following syntax fail:

scala> (integers take 10 toList) last
res27: Int = 11

scala> integers take 10 toList last
<console>:24: error: not found: value last
integers take 10 toList last

I find wrapping things in brackets cumbersome, is there a shorthand I am not aware of?

Answer Source

You're probably thinking that 1 #:: integers map(x=>nextInteger(x)) is parsed as 1 #:: (integers map(x=>nextInteger(x))) while it is actually parsed as (1 #:: integers).map(x=>nextInteger(x)). Adding parens fixes your problem:

val integers: Stream[Int] = 1 #:: (integers map nextInteger)

(Notice that since nextInteger is just a function, you don't need to make a lambda for it, and since Stream is already lazy, making integers lazy is unnecessary)

As to your edit, check out this excellent answer on the matter. In short: no there is no easy way. The thing is that unless you already know the arity of the functions involved, having something like what you suggest work would be hell for the next person reading your code... For example,

myList foo bar baz

Might be be as well as and you wouldn't know without checking the definitions of foo, bar, and baz. Scala decides to eliminate this ambiguity - it is always the latter.