Skip to content

Commit 49d6dba

Browse files
committed
Clean up control.TailCalls
1 parent ea9c2ce commit 49d6dba

File tree

1 file changed

+34
-33
lines changed

1 file changed

+34
-33
lines changed

library/src/scala/util/control/TailCalls.scala

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@
1010
* additional information regarding copyright ownership.
1111
*/
1212

13-
package scala
14-
package util.control
13+
package scala.util.control
14+
15+
import annotation.tailrec
1516

1617
/** Methods exported by this object implement tail calls via trampolining.
17-
* Tail calling methods have to return their result using `done` or call the
18-
* next method using `tailcall`. Both return a `TailRec` object. The result
19-
* of evaluating a tailcalling function can be retrieved from a `Tailrec`
18+
*
19+
* Tail calling methods must either return their result using `done` or call the
20+
* next method using `tailcall`. Both return an instance of `TailRec`. The result
21+
* of evaluating a tailcalling function can be retrieved from a `TailRec`
2022
* value using method `result`.
23+
*
2124
* Implemented as described in "Stackless Scala with Free Monads"
2225
* [[https://blog.higher-order.com/assets/trampolines.pdf]]
2326
*
@@ -44,67 +47,65 @@ package util.control
4447
*/
4548
object TailCalls {
4649

47-
/** This class represents a tailcalling computation
50+
/** This class represents a tailcalling computation.
4851
*/
4952
sealed abstract class TailRec[+A] {
5053

5154
/** Continue the computation with `f`. */
52-
final def map[B](f: A => B): TailRec[B] =
53-
flatMap(a => Call(() => Done(f(a))))
55+
final def map[B](f: A => B): TailRec[B] = flatMap(a => Call(() => Done(f(a))))
5456

5557
/** Continue the computation with `f` and merge the trampolining
56-
* of this computation with that of `f`. */
57-
final def flatMap[B](f: A => TailRec[B]): TailRec[B] =
58-
this match {
59-
case Done(a) => Call(() => f(a))
60-
case c @ Call(_) => Cont(c, f)
61-
// Take advantage of the monad associative law to optimize the size of the required stack
62-
case c: Cont[a1, b1] => Cont(c.a, (x: a1) => c.f(x) flatMap f)
63-
}
58+
* of this computation with that of `f`. */
59+
final def flatMap[B](f: A => TailRec[B]): TailRec[B] = this match {
60+
case Done(a) => Call(() => f(a))
61+
case Call(_) => Cont(this, f)
62+
// Take advantage of the monad associative law to optimize the size of the required stack
63+
case c: Cont[a1, b1] => Cont(c.a, (x: a1) => c.f(x).flatMap(f))
64+
}
6465

6566
/** Returns either the next step of the tailcalling computation,
6667
* or the result if there are no more steps. */
67-
@annotation.tailrec final def resume: Either[() => TailRec[A], A] = this match {
68-
case Done(a) => Right(a)
69-
case Call(k) => Left(k)
68+
@tailrec final def resume: Either[() => TailRec[A], A] = this match {
69+
case Done(a) => Right(a)
70+
case Call(k) => Left(k)
7071
case Cont(a, f) => a match {
71-
case Done(v) => f(v).resume
72-
case Call(k) => Left(() => k().flatMap(f))
73-
case Cont(b, g) => b.flatMap(x => g(x) flatMap f).resume
72+
case Done(v) => f(v).resume
73+
case Call(k) => Left(() => k().flatMap(f))
74+
case Cont(b, g) => b.flatMap(x => g(x).flatMap(f)).resume
7475
}
7576
}
7677

7778
/** Returns the result of the tailcalling computation.
7879
*/
79-
@annotation.tailrec final def result: A = this match {
80-
case Done(a) => a
81-
case Call(t) => t().result
80+
@tailrec final def result: A = this match {
81+
case Done(a) => a
82+
case Call(t) => t().result
8283
case Cont(a, f) => a match {
83-
case Done(v) => f(v).result
84-
case Call(t) => t().flatMap(f).result
85-
case Cont(b, g) => b.flatMap(x => g(x) flatMap f).result
84+
case Done(v) => f(v).result
85+
case Call(t) => t().flatMap(f).result
86+
case Cont(b, g) => b.flatMap(x => g(x).flatMap(f)).result
8687
}
8788
}
8889
}
8990

90-
/** Internal class representing a tailcall */
91+
/** Internal class representing a tailcall. */
9192
protected case class Call[A](rest: () => TailRec[A]) extends TailRec[A]
9293

9394
/** Internal class representing the final result returned from a tailcalling
94-
* computation */
95+
* computation. */
9596
protected case class Done[A](value: A) extends TailRec[A]
9697

9798
/** Internal class representing a continuation with function A => TailRec[B].
98-
* It is needed for the flatMap to be implemented. */
99+
* It is needed for the flatMap to be implemented. */
99100
protected case class Cont[A, B](a: TailRec[A], f: A => TailRec[B]) extends TailRec[B]
100101

101-
/** Performs a tailcall
102+
/** Perform a tailcall.
102103
* @param rest the expression to be evaluated in the tailcall
103104
* @return a `TailRec` object representing the expression `rest`
104105
*/
105106
def tailcall[A](rest: => TailRec[A]): TailRec[A] = Call(() => rest)
106107

107-
/** Used to return final result from tailcalling computation
108+
/** Return the final result from a tailcalling computation.
108109
* @param `result` the result value
109110
* @return a `TailRec` object representing a computation which immediately
110111
* returns `result`

0 commit comments

Comments
 (0)