You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
== Structural Recursion and Corecursion for Codata
3
+
<sec:codata-structural>
3
4
4
5
5
6
In this section we'll build a library for streams, also known as lazy lists. These are the codata equivalent of lists. Whereas a list must have a finite length, streams have an infinite length. We'll use this example to explore structural recursion and structural corecursion as applied to codata.
@@ -582,13 +583,13 @@ twos.take(5)
582
583
583
584
We get the same result whether we use a method or a `lazy val`, because we are assuming that we are only dealing with pure computations that have no dependency on state that might change. In this case a `lazy val` simply consumes additional space to save on time.
584
585
585
-
Recomputing a result every time it is needed is known as *call by name*, while caching the result the first time it is computed is known as *call by need*. These two different *evaluation strategies* can be applied to individual values, as we've done here, or across an entire programming. Haskell, for example, uses call by need; all values in Haskell are only computed the first time they are needed. Call by need is also commonly known as *lazy evaluation*. Another alternative, called *call by value*, computes results when they are defined instead of waiting until they are needed. This is the default in Scala.
586
+
Recomputing a result every time it is needed is known as *call-by-name*, while caching the result the first time it is computed is known as *call-by-need*. These two different *evaluation strategies* can be applied to individual values, as we've done here, or across an entire programming. Haskell, for example, uses call-by-need; all values in Haskell are only computed the first time they are needed. call-by-need is also commonly known as *lazy evaluation*. Another alternative, called *call-by-value*, computes results when they are defined instead of waiting until they are needed. This is the default in Scala.
586
587
587
-
We can illustrate the difference between call by name and call by need if we use an impure computation.
588
+
We can illustrate the difference between call-by-name and call-by-need if we use an impure computation.
588
589
For example, we can define a stream of random numbers.
589
590
Random number generators depend on some internal state.
590
591
591
-
Here's the call by name implementation, using the methods we have already defined.
592
+
Here's the call-by-name implementation, using the methods we have already defined.
592
593
593
594
```scala mdoc:silent
594
595
import scala.util.Random
@@ -605,7 +606,7 @@ randoms.take(5)
605
606
randoms.take(5)
606
607
```
607
608
608
-
Now let's define the same stream in a call by need style, using `lazy val`.
609
+
Now let's define the same stream in a call-by-need style, using `lazy val`.
609
610
610
611
```scala mdoc:silent
611
612
val randomsByNeed: Stream[Double] =
@@ -622,7 +623,7 @@ randomsByNeed.take(5)
622
623
randomsByNeed.take(5)
623
624
```
624
625
625
-
If we wanted a stream that had a different random number for each element but those numbers were constant, we could redefine `unfold` to use call by need.
626
+
If we wanted a stream that had a different random number for each element but those numbers were constant, we could redefine `unfold` to use call-by-need.
626
627
627
628
```scala mdoc:silent
628
629
def unfoldByNeed[A, B](seed: A, f: A => B, next: A => A): Stream[B] =
0 commit comments