diff --git a/dist/scala-with-cats.epub b/dist/scala-with-cats.epub index 6f875a91..7772a650 100644 Binary files a/dist/scala-with-cats.epub and b/dist/scala-with-cats.epub differ diff --git a/dist/scala-with-cats.html b/dist/scala-with-cats.html index a7239a86..7c927f74 100644 --- a/dist/scala-with-cats.html +++ b/dist/scala-with-cats.html @@ -9911,19 +9911,19 @@
randoms.take(5)
// res19: List[Double] = List(
-// 0.9208355396390738,
-// 0.5891123064177592,
-// 0.3863326062180119,
-// 0.687954952883182,
-// 0.6468041118151546
+// 0.8754399846226281,
+// 0.8668667032261326,
+// 0.8096271659320063,
+// 0.04478363704070387,
+// 0.5750767027125137
// )
randoms.take(5)
// res20: List[Double] = List(
-// 0.04387754397318444,
-// 0.6949346853301758,
-// 0.01805741082006429,
-// 0.2880136805156752,
-// 0.3376311452930971
+// 0.21185116186743658,
+// 0.3035319210159354,
+// 0.40533845806072466,
+// 0.7381884666336406,
+// 0.34627861681944083
// )
Now let’s define the same stream in a call by need style, using
lazy val
.
randomsByNeed.take(5)
// res21: List[Double] = List(
-// 0.5447118477682825,
-// 0.5447118477682825,
-// 0.5447118477682825,
-// 0.5447118477682825,
-// 0.5447118477682825
+// 0.45279732072322587,
+// 0.45279732072322587,
+// 0.45279732072322587,
+// 0.45279732072322587,
+// 0.45279732072322587
// )
randomsByNeed.take(5)
// res22: List[Double] = List(
-// 0.5447118477682825,
-// 0.5447118477682825,
-// 0.5447118477682825,
-// 0.5447118477682825,
-// 0.5447118477682825
+// 0.45279732072322587,
+// 0.45279732072322587,
+// 0.45279732072322587,
+// 0.45279732072322587,
+// 0.45279732072322587
// )
If we wanted a stream that had a different random number for each element but those numbers were constant, we could redefine @@ -9968,19 +9968,19 @@
randomsByNeed2.take(5)
// res23: List[Double] = List(
-// 0.8940500869022447,
-// 0.3731405707113826,
-// 0.6282375992855587,
-// 0.6939341360566086,
-// 0.3712126709086925
+// 0.12069142328271365,
+// 0.3166763080822603,
+// 0.05042767731721132,
+// 0.8940362612630662,
+// 0.8562348066084499
// )
randomsByNeed2.take(5)
// res24: List[Double] = List(
-// 0.8940500869022447,
-// 0.3731405707113826,
-// 0.6282375992855587,
-// 0.6939341360566086,
-// 0.3712126709086925
+// 0.12069142328271365,
+// 0.3166763080822603,
+// 0.05042767731721132,
+// 0.8940362612630662,
+// 0.8562348066084499
// )
These subtleties are one of the reasons that functional programmers try to avoid using state as far as possible.
@@ -11097,7 +11097,7 @@summon[JsonWriter[String]]
-// res6: JsonWriter[String] = repl.MdocSession$MdocApp3$JsonWriter$$anon$7@12a11c50
+// res6: JsonWriter[String] = repl.MdocSession$MdocApp3$JsonWriter$$anon$7@11022749
Most type classes in Cats provide other means to summon
instances. However, summon
is a good fallback for
debugging purposes. We can insert a call to summon
@@ -13122,7 +13122,7 @@
new Date().show
-// res2: String = "1723213389727ms since the epoch."
However, Cats also provides a couple of convenient methods to
simplify the process. There are two construction methods on the
companion object of Show
that we can use to define
@@ -14450,10 +14450,10 @@
val func = (x: Int) => x + 1
-// func: Function1[Int, Int] = repl.MdocSession$MdocApp0$$$Lambda/0x00007fd16b11ca10@50c85e5f
+// func: Function1[Int, Int] = repl.MdocSession$MdocApp0$$$Lambda/0x00007f438ae98a10@2c84be94
val liftedFunc = Functor[Option].lift(func)
-// liftedFunc: Function1[Option[Int], Option[Int]] = cats.Functor$$Lambda/0x00007fd16b1091c8@61233264
+// liftedFunc: Function1[Option[Int], Option[Int]] = cats.Functor$$Lambda/0x00007f438aecf568@41aee62c
liftedFunc(Option(1))
// res1: Option[Int] = Some(value = 2)
@@ -15156,7 +15156,7 @@ val func3 = func1.map(func2)
-// func3: Function1[Int, Double] = cats.instances.Function1Instances0$$anon$11$$Lambda/0x00007fd16b0d62f0@42a92565
Function1
has two type parameters (the function
argument and the result type):
trait Function1[-A, +B] {
@@ -15322,7 +15322,7 @@ val func2b: Double <= Double = func2
val func3c = func2b.contramap(func1)
-// func3c: Function1[Int, Double] = scala.Function1$$Lambda/0x00007fd16b0843c8@2774ca70
The difference between func2
and func2b
is purely syntactic—both refer to the same value and the type
aliases are otherwise completely compatible. Incredibly, however,
@@ -15849,7 +15849,7 @@
import scala.concurrent.ExecutionContext.Implicits.global
val fm = Monad[Future]
-// fm: Monad[[T >: Nothing <: Any] => Future[T]] = cats.instances.FutureInstances$$anon$1@588ff931
The Monad
instance uses the captured
ExecutionContext
for subsequent calls to
pure
and flatMap
:
This is an example of call-by-value evaluation:
These are the properties of call-by-name evaluation:
Let’s summarize. There are two properties of interest:
import cats.Eval
val now = Eval.now(math.random() + 1000)
-// now: Eval[Double] = Now(value = 1000.2789904655458)
+// now: Eval[Double] = Now(value = 1000.0855198365294)
val always = Eval.always(math.random() + 3000)
-// always: Eval[Double] = cats.Always@76cf20f0
+// always: Eval[Double] = cats.Always@52ba4f69
val later = Eval.later(math.random() + 2000)
-// later: Eval[Double] = cats.Later@402829e2
We can extract the result of an Eval
using its
value
method:
.value
- now// res6: Double = 1000.2789904655458
+// res6: Double = 1000.0855198365294
.value
- always// res7: Double = 3000.397989875432
+// res7: Double = 3000.2588105234813
.value
- later// res8: Double = 2000.0977959520712
Each type of Eval
calculates its result using one of
the evaluation models defined above. Eval.now
captures
a value right now. Its semantics are similar to a
@@ -16584,39 +16584,39 @@
Eval.always
captures a lazy computation, similar to
a def
:
val y = Eval.always{
println("Computing Y")
.random()
math}
-// y: Eval[Double] = cats.Always@51fc1d
+// y: Eval[Double] = cats.Always@17e51b5e
.value // first access
y// Computing Y
-// res12: Double = 0.7103047555919701
+// res12: Double = 0.5136525236943111
.value // second access
y// Computing Y
-// res13: Double = 0.5434137244149811
Finally, Eval.later
captures a lazy, memoized
computation, similar to a lazy val
:
val z = Eval.later{
println("Computing Z")
.random()
math}
-// z: Eval[Double] = cats.Later@7855c76e
+// z: Eval[Double] = cats.Later@e7d6f7
.value // first access
z// Computing Z
-// res14: Double = 0.7290651872811074
+// res14: Double = 0.5130255926081816
.value // second access
- z// res15: Double = 0.7290651872811074
The three behaviours are summarized below: