Fold is designed to allow laziness/short-circuiting in foldRight.
It is a sum type that has three possible subtypes:
Return(a): stop the fold with a value of a.
Continue(f): continue the fold, suspending the computation f for this step.
Pass: continue the fold, with no computation for this step.
The meaning of these types can be made more clear with an example
of the foldRight method in action. Here's a method to count how many
elements appear in a list before the value 3:
def f(n: Int): Fold[Int] =
if (n == 3) Fold.Return(0) else Fold.Continue(_ + 1)
val count: Lazy[Int] = List(1,2,3,4).foldRight(Lazy(0))(f)
When we call count.value, the following occurs:
f(1) produces res0: Continue(_ + 1)
f(2) produces res1: Continue(_ + 1)
f(3) produces res2: Return(0)
Now we unwind back through the continue instances:
res2 returns 0
res1(0) returns 1
res0(1) returns 2
And so the result is 2.
This code searches an infinite stream for 77:
val found: Lazy[Boolean] =
Stream.from(0).foldRight(Lazy(false)) { n =>if (n == 77) Fold.Return(true) else Fold.Pass
}
Here's another example that sums the list until it reaches a
negative number:
val sum: Lazy[Double] =
numbers.foldRight(Lazy(0.0)) { n =>if (n < 0) Fold.Return(0.0) else Fold.Continue(n + _)
}
This strange example counts an infinite stream. Since the result is
lazy, it will only hang the program once count.value is called:
Fold is designed to allow laziness/short-circuiting in foldRight.
It is a sum type that has three possible subtypes:
Return(a)
: stop the fold with a value ofa
.Continue(f)
: continue the fold, suspending the computationf
for this step.Pass
: continue the fold, with no computation for this step.The meaning of these types can be made more clear with an example of the foldRight method in action. Here's a method to count how many elements appear in a list before the value 3:
When we call
count.value
, the following occurs:f(1)
producesres0: Continue(_ + 1)
f(2)
producesres1: Continue(_ + 1)
f(3)
producesres2: Return(0)
Now we unwind back through the continue instances:
res2
returns0
res1(0)
returns1
res0(1)
returns2
And so the result is 2.
This code searches an infinite stream for 77:
Here's another example that sums the list until it reaches a negative number:
This strange example counts an infinite stream. Since the result is lazy, it will only hang the program once
count.value
is called:You can even implement foldLeft in terms of foldRight (!):
(In practice you would not want to use the
foldl
because it is not stack-safe.)