10
10
* additional information regarding copyright ownership.
11
11
*/
12
12
13
- package scala
14
- package util .control
13
+ package scala .util .control
14
+
15
+ import annotation .tailrec
15
16
16
17
/** 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`
20
22
* value using method `result`.
23
+ *
21
24
* Implemented as described in "Stackless Scala with Free Monads"
22
25
* [[https://blog.higher-order.com/assets/trampolines.pdf ]]
23
26
*
@@ -44,67 +47,65 @@ package util.control
44
47
*/
45
48
object TailCalls {
46
49
47
- /** This class represents a tailcalling computation
50
+ /** This class represents a tailcalling computation.
48
51
*/
49
52
sealed abstract class TailRec [+ A ] {
50
53
51
54
/** 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))))
54
56
55
57
/** 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
+ }
64
65
65
66
/** Returns either the next step of the tailcalling computation,
66
67
* 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)
70
71
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
74
75
}
75
76
}
76
77
77
78
/** Returns the result of the tailcalling computation.
78
79
*/
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
82
83
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
86
87
}
87
88
}
88
89
}
89
90
90
- /** Internal class representing a tailcall */
91
+ /** Internal class representing a tailcall. */
91
92
protected case class Call [A ](rest : () => TailRec [A ]) extends TailRec [A ]
92
93
93
94
/** Internal class representing the final result returned from a tailcalling
94
- * computation */
95
+ * computation. */
95
96
protected case class Done [A ](value : A ) extends TailRec [A ]
96
97
97
98
/** 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. */
99
100
protected case class Cont [A , B ](a : TailRec [A ], f : A => TailRec [B ]) extends TailRec [B ]
100
101
101
- /** Performs a tailcall
102
+ /** Perform a tailcall.
102
103
* @param rest the expression to be evaluated in the tailcall
103
104
* @return a `TailRec` object representing the expression `rest`
104
105
*/
105
106
def tailcall [A ](rest : => TailRec [A ]): TailRec [A ] = Call (() => rest)
106
107
107
- /** Used to return final result from tailcalling computation
108
+ /** Return the final result from a tailcalling computation.
108
109
* @param `result` the result value
109
110
* @return a `TailRec` object representing a computation which immediately
110
111
* returns `result`
0 commit comments