How lazily interpreted in a recursive context?

Here is the code from FPIS

object test2 {

  //a naive IO monad
  sealed trait IO[A] { self =>
    def run: A
    def map[B](f: A => B): IO[B] = new IO[B] { def run = f(self.run) }
    def flatMap[B](f: A => IO[B]): IO[B] = {
      println("calling IO.flatMap")
      new IO[B] {
        def run = {
            println("calling run from flatMap result")
            f(self.run).run
        }
     }
    }
  }

  object IO {
    def unit[A](a: => A): IO[A] = new IO[A] { def run = a }
    def apply[A](a: => A): IO[A] = unit(a) // syntax for IO { .. }
  }

  //composer in question
  def forever[A,B](a: IO[A]): IO[B] = {
    lazy val t: IO[B] = a flatMap (_ => t)
    t
  }

  def PrintLine(msg: String) = IO { println(msg) }

  def say = forever(PrintLine("Still Going..")).run
}

test2.say will print thousands of "Still Going" before the stack overflows. But I don’t know exactly how this happens.

The result is as follows:
scala> test2.say
call IO.flatMap // only once
call from flatMap result
Still coming ..
call from flatMap result
Still coming ..

... // repeated until

When the forever function returns, is lazy val t fully computed (cached)? And the flatMap method seems to be called only once (I'm adding print instructions), which forever takes into account the recursive definition. Why?

===========
- , B [A, B] . Scala .

[Unit, Double], forever [Unit, String] .., . .

+4
3

, forever , lazy val t ()?

, ?

. , :

def repeat(n: Int): Seq[Int] {
  lazy val expensive = "some expensive computation"
  Seq.fill(n)(expensive)
  // when n == 0, the 'expensive' computation will be skipped
  // when n > 1, the 'expensive' computation will only be computed once
}

, , , flatMap ( ), . ?

, , , , @

19/04/2017

, :-) lazy val - .

, forever(a).run:

  • forever(a)

  • { lazy val t = a flatMap(_ => t) }

  • { lazy val t = new IO[B] { def run() = { ... t.run } }

t , flatMap new IO[B] 2 3 , "" .

run() 3 t.run , , , .

, forever, , :

  def forever[A, B](a: IO[A]): IO[B] = {
    new IO[B] {
      @tailrec
      override def run: B = {
        a.run
        run
      }
    }
  }
+2

forever , , a . , .

t :

t = a flatMap (_ => t)

t = a flatMap (_ => a flatMap (_ => t))

t = a flatMap (_ => a flatMap (_ => a flatMap (_ => t)))

..

Lazy - . , " " ( , ), ( , ).

:

val rec: Int = 1 + rec
println(rec) // prints 1, "rec" in the body is initialized to default value 0


def foo() = {
  val rec: Int = 1 + rec // ERROR: forward reference extends over definition of value rec
  println(rec)
}

, . , . :

def run = {
  println("calling run from flatMap result")
  f(self.run).run
}

run (. self.run). , self.run , f ; , run().

t forever, IO, flatMaps (, flatMap, " " ). run , , f. flatMap ( flatMap), , flatMap, run f, IO, run, f, IO, run, f, IO, run...

+3
  new IO[B] {
    def run = {
        println("calling run from flatMap result")
        f(self.run).run
    }
 }

, : def run def.

:

f(self.run).run
       |-----|--- println
             |--- f(self.run).run
                         |-----|------println
                               |------f(self.run).run
                                             |------ (repeating)

f (self.run) / val t
f: _ = > t t, IS IO [B], , , .

, .

, val .

+2

Source: https://habr.com/ru/post/1675116/


All Articles