From a0ffefae01656e04a7033c966b0d69091021978d Mon Sep 17 00:00:00 2001 From: Peter Becich Date: Fri, 3 Jul 2015 13:22:27 -0700 Subject: [PATCH] Including Errata's corrected trampolining example from Section 13.3.2 saves some trouble for those who wouldn't check the Errata. --- .../src/main/scala/fpinscala/iomonad/IO.scala | 65 +++++++++++++++++++ .../src/main/scala/fpinscala/iomonad/IO.scala | 64 +++++++++++++++++- 2 files changed, 128 insertions(+), 1 deletion(-) diff --git a/answers/src/main/scala/fpinscala/iomonad/IO.scala b/answers/src/main/scala/fpinscala/iomonad/IO.scala index b3140aa599..6994bd81e2 100644 --- a/answers/src/main/scala/fpinscala/iomonad/IO.scala +++ b/answers/src/main/scala/fpinscala/iomonad/IO.scala @@ -175,6 +175,9 @@ object IO2a { object IO extends Monad[IO] { // Notice that none of these operations DO anything def unit[A](a: => A): IO[A] = Return(a) def flatMap[A,B](a: IO[A])(f: A => IO[B]): IO[B] = a flatMap f + def suspend[A](a: => IO[A]) = + Suspend(() => ()).flatMap { _ => a } + } def printLine(s: String): IO[Unit] = @@ -202,6 +205,44 @@ object IO2a { } } +object IO2aTests { + import IO2a._ + + /* + Pg 240: REPL session has a typo, should be: + + val g = List.fill(100000)(f).foldLeft(f) { + (a, b) => x => Suspend(() => ()).flatMap { _ => a(x).flatMap(b)} + } + + Note: we could write a little helper function to make this nicer: + + def suspend[A](a: => IO[A]) = Suspend(() => ()).flatMap { _ => a } + + val g = List.fill(100000)(f).foldLeft(f) { + (a, b) => x => suspend { a(x).flatMap(b) } + } + */ + + val f: Int => IO[Int] = (i: Int) => Return(i) + + val g: Int => IO[Int] = + List.fill(10000)(f).foldLeft(f){ + (a: Function1[Int, IO[Int]], + b: Function1[Int, IO[Int]]) => { + (x: Int) => IO.suspend(a(x).flatMap(b)) + } + } + + def main(args: Array[String]): Unit = { + val gFortyTwo = g(42) + println("g(42) = " + gFortyTwo) + println("run(g(42)) = " + run(gFortyTwo)) + } +} + + + object IO2b { /* @@ -225,6 +266,9 @@ object IO2b { object TailRec extends Monad[TailRec] { def unit[A](a: => A): TailRec[A] = Return(a) def flatMap[A,B](a: TailRec[A])(f: A => TailRec[B]): TailRec[B] = a flatMap f + def suspend[A](a: => TailRec[A]) = + Suspend(() => ()).flatMap { _ => a } + } @annotation.tailrec def run[A](t: TailRec[A]): A = t match { @@ -238,6 +282,27 @@ object IO2b { } } +object IO2bTests { + import IO2b._ + + val f: Int => TailRec[Int] = (i: Int) => Return(i) + + val g: Int => TailRec[Int] = + List.fill(10000)(f).foldLeft(f){ + (a: Function1[Int, TailRec[Int]], + b: Function1[Int, TailRec[Int]]) => { + (x: Int) => TailRec.suspend(a(x).flatMap(b)) + } + } + + def main(args: Array[String]): Unit = { + val gFortyTwo = g(42) + println("g(42) = " + gFortyTwo) + println("run(g(42)) = " + run(gFortyTwo)) + } +} + + object IO2c { import fpinscala.parallelism.Nonblocking._ diff --git a/exercises/src/main/scala/fpinscala/iomonad/IO.scala b/exercises/src/main/scala/fpinscala/iomonad/IO.scala index 0d13562924..53979d53a2 100644 --- a/exercises/src/main/scala/fpinscala/iomonad/IO.scala +++ b/exercises/src/main/scala/fpinscala/iomonad/IO.scala @@ -175,6 +175,8 @@ object IO2a { object IO extends Monad[IO] { // Notice that none of these operations DO anything def unit[A](a: => A): IO[A] = Return(a) def flatMap[A,B](a: IO[A])(f: A => IO[B]): IO[B] = a flatMap f + def suspend[A](a: => IO[A]) = + Suspend(() => ()).flatMap { _ => a } } def printLine(s: String): IO[Unit] = @@ -202,6 +204,43 @@ object IO2a { } } +object IO2aTests { + import IO2a._ + + /* + Pg 240: REPL session has a typo, should be: + + val g = List.fill(100000)(f).foldLeft(f) { + (a, b) => x => Suspend(() => ()).flatMap { _ => a(x).flatMap(b)} + } + + Note: we could write a little helper function to make this nicer: + + def suspend[A](a: => IO[A]) = Suspend(() => ()).flatMap { _ => a } + + val g = List.fill(100000)(f).foldLeft(f) { + (a, b) => x => suspend { a(x).flatMap(b) } + } + */ + + val f: Int => IO[Int] = (i: Int) => Return(i) + + val g: Int => IO[Int] = + List.fill(10000)(f).foldLeft(f){ + (a: Function1[Int, IO[Int]], + b: Function1[Int, IO[Int]]) => { + (x: Int) => IO.suspend(a(x).flatMap(b)) + } + } + + def main(args: Array[String]): Unit = { + val gFortyTwo = g(42) + println("g(42) = " + gFortyTwo) + println("run(g(42)) = " + run(gFortyTwo)) + } +} + + object IO2b { /* @@ -224,7 +263,10 @@ object IO2b { object TailRec extends Monad[TailRec] { def unit[A](a: => A): TailRec[A] = Return(a) - def flatMap[A,B](a: TailRec[A])(f: A => TailRec[B]): TailRec[B] = a flatMap f + def flatMap[A,B](a: TailRec[A])(f: A => TailRec[B]): TailRec[B] = + a flatMap f + def suspend[A](a: => TailRec[A]) = + Suspend(() => ()).flatMap { _ => a } } @annotation.tailrec def run[A](t: TailRec[A]): A = t match { @@ -238,6 +280,26 @@ object IO2b { } } +object IO2bTests { + import IO2b._ + + val f: Int => TailRec[Int] = (i: Int) => Return(i) + + val g: Int => TailRec[Int] = + List.fill(10000)(f).foldLeft(f){ + (a: Function1[Int, TailRec[Int]], + b: Function1[Int, TailRec[Int]]) => { + (x: Int) => TailRec.suspend(a(x).flatMap(b)) + } + } + + def main(args: Array[String]): Unit = { + val gFortyTwo = g(42) + println("g(42) = " + gFortyTwo) + println("run(g(42)) = " + run(gFortyTwo)) + } +} + object IO2c { import fpinscala.parallelism.Nonblocking._