Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional programming in scala - infinite streams

I'm working through the exercises and concepts of the book: Functional Programming in Scala. Say I need to define a constant function, which returns an infinite stream by the given value.

Here is my version:

def constant[A](a: A): Stream[A] = Stream.cons(a, constant(a))

and the answer in GitHub:

def constant[A](a: A): Stream[A] = {
  lazy val tail: Stream[A] = Cons(() => a, () => tail)
  tail
}

The comment says the latter is more efficient than the former since it's just one object referencing itself. I can't understand this, any help would be greatly appreciated. (and sorry for my broken English :)

like image 490
zhang-yuan Avatar asked Oct 24 '17 00:10

zhang-yuan


People also ask

Can streams support Functional Programming?

Streams will use the same functional programming concepts to iterate over collections of data in the functional style.

Does Scala support Functional Programming?

Scala is a language that features full support of Functional Programming as well as the Object-Oriented Paradigm. It is one of the most widely utilized languages by the Functional community, up to par with F#, and Haskell, Clojure, among others.

Is stream Functional Programming?

Streams in Java provide a functional approach to process a collection of objects. Stream. java provides different methods to process list elements, map(), flatMap(), filter(), sorted() etc, each of which takes a functional interface type as an argument.

What is Functional Programming language in Scala?

Functional programming (FP) is a style of software development emphasizing functions that don't depend on program state. Functional code is easier to test and reuse, simpler to parallelize, and less prone to bugs than other code. Scala is an emerging JVM language that offers strong support for FP.


1 Answers

Say you define constant the first way. Now,

constant(something)

This is one Cons cell, and it has a reference to the lazy values something and constant(something)

Cons(() => something, () => constant(something))

Now, let's try to get the 1000th element. We need to evaluate the tail, because we need to go deeper than just the first element. So, we execute constant(something), and we get a new Cons cell that looks just like the original:

Cons(() => something, () => constant(something))

And we try to get 999th element of this Stream. This is inefficient, because this object is the same as the one from before, so we just wasted our time making it. We will continue to waste time and memory making 1000 identical Cons cells. (Excuse the terrible drawing.)

Graph of first version

Now, define constant the second way.

constant(something)
{ lazy val self = Cons(something, self); self }

Now, your Stream simply has a reference to itself. Getting the tail of this Stream does not create a new Cons cell; it simply returns the original stream (self.tail eq self), which means you waste no memory, and the time cost goes down because you also don't waste time allocating and filling that memory.

Graph of second version

like image 87
HTNW Avatar answered Oct 30 '22 16:10

HTNW