-
Notifications
You must be signed in to change notification settings - Fork 29
/
Return.scala
68 lines (63 loc) · 2.31 KB
/
Return.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.thoughtworks.dsl.keywords
import com.thoughtworks.dsl.Dsl
import com.thoughtworks.dsl.Dsl.Keyword
import scala.language.implicitConversions
/** A [[Dsl.Keyword]] to early return a lifted value from the enclosing function.
*
* @author 杨博 (Yang Bo)
* @example Suppose you are generating a random integer less than 100,
* whose first digit and second digit is different.
* A solution is generating integers in an infinite loop,
* and [[Return]] from the loop when the generated integer conforms with requirements.
*
* {{{
* import scala.util.Random
* import scala.util.control.TailCalls
* import scala.util.control.TailCalls.TailRec
* def randomInt(): TailRec[Int] = {
* while (true) {
* val r = Random.nextInt(100)
* if (r % 10 != r / 10) {
* !Return(TailCalls.done(r))
* }
* }
* throw new AssertionError("Unreachable code");
* }
*
* val r = randomInt().result
* r should be < 100
* r % 10 should not be r / 10
* }}}
*
* @example Since this [[Return]] keyword can automatically lift the return type,
* `TailCalls.done` can be omitted.
*
* {{{
* import scala.util.Random
* import scala.util.control.TailCalls
* import scala.util.control.TailCalls.TailRec
* def randomInt(): TailRec[Int] = {
* while (true) {
* val r = Random.nextInt(100)
* if (r % 10 != r / 10) {
* !Return(r)
* }
* }
* throw new AssertionError("Unreachable code");
* }
*
* val r = randomInt().result
* r should be < 100
* r % 10 should not be r / 10
* }}}
*
*/
final case class Return[ReturnValue](returnValue: ReturnValue) extends AnyVal with Keyword[Return[ReturnValue], Nothing]
object Return {
implicit def returnDsl[ReturnValue, Domain >: ReturnValue]: Dsl[Return[ReturnValue], Domain, Nothing] =
new Dsl[Return[ReturnValue], Domain, Nothing] {
def cpsApply(keyword: Return[ReturnValue], handler: Nothing => Domain): Domain = {
keyword.returnValue
}
}
}