LazyList не пуст. Проверьте документацию Stream:
/** Construct a stream consisting of a given first element followed by elements
* from a lazily evaluated Stream.
*/
def #::[B >: A](hd: B): Stream[B] = cons(hd, tl)
Так, по крайней мере, ваш Stream / LazyList имеет первый элемент (оцененный), и это 1 из
1 #:: fibbonaciNumbers.scanLeft...
Вторым элементом в списке является 1 из scanLeft ... и затем scanLeft вступает во владение, чтобы сгенерировать остальные элементы 2, 3, 5 ... но они будут оцениваться только при необходимости. Но когда они нужны? ... когда вы звоните
println("The result is " + fibbonaciNumbersSum(4000000))
и это вызовет оценку
fibbonaciNumbers.takeWhile(_ <= limit).filter(_ % 2 == 0).sum
Таким образом, каждый элемент в Stream / LazyList будет оцениваться при условии, что они меньше предела, и фильтрация и суммирование будут выполнены.