1
+ import scala .util .*
2
+
3
+ /** boundary/break as a replacement for non-local returns */
4
+ def indexOf [T ](xs : List [T ], elem : T ): Int =
5
+ boundary :
6
+ for (x, i) <- xs.zipWithIndex do
7
+ if x == elem then break(i)
8
+ - 1
9
+
10
+ def breakTest () =
11
+ println(" breakTest" )
12
+ assert(indexOf(List (1 , 2 , 3 ), 2 ) == 1 )
13
+ assert(indexOf(List (1 , 2 , 3 ), 0 ) == - 1 )
14
+
15
+ /** traverse becomes trivial to write */
16
+ def traverse [T ](xs : List [Option [T ]]): Option [List [T ]] =
17
+ optional(xs.map(_.? ))
18
+
19
+ def optTest () =
20
+ println(" optTest" )
21
+ assert(traverse(List (Some (1 ), Some (2 ), Some (3 ))) == Some (List (1 , 2 , 3 )))
22
+ assert(traverse(List (Some (1 ), None , Some (3 ))) == None )
23
+
24
+ /** A check function returning a Result[Unit, _] */
25
+ inline def check [E ](p : Boolean , err : E ): Result [Unit , E ] =
26
+ if p then Ok (()) else Err (err)
27
+
28
+ /** Another variant of a check function that returns directly to the given
29
+ * label in case of error.
30
+ */
31
+ inline def check_! [E ](p : Boolean , err : E )(using l : boundary.Label [Err [E ]]): Unit =
32
+ if p then () else break(Err (err))
33
+
34
+ /** Use `Result` to convert exceptions to `Err` values */
35
+ def parseDouble (s : String ): Result [Double , Exception ] =
36
+ Result (s.toDouble)
37
+
38
+ def parseDoubles (ss : List [String ]): Result [List [Double ], Exception ] =
39
+ respond :
40
+ ss.map(parseDouble(_).? )
41
+
42
+ /** Demonstrate combination of `check` and `.?`. */
43
+ def trySqrt (x : Double ) = // inferred: Result[Double, String]
44
+ respond :
45
+ check(x >= 0 , s " cannot take sqrt of negative $x" ).? // direct jump
46
+ math.sqrt(x)
47
+
48
+ /** Instead of `check(...).?` one can also use `check_!(...)`.
49
+ * Note use of `mapErr` to convert Exception errors to String errors.
50
+ */
51
+ def sumRoots (xs : List [String ]) = // inferred: Result[Double, String]
52
+ respond :
53
+ check_!(xs.nonEmpty, " list is empty" ) // direct jump
54
+ val ys = parseDoubles(xs).mapErr(_.toString).? // direct jump
55
+ ys.reduce((x, y) => x + trySqrt(y).? ) // need exception to propagate `Err`
56
+
57
+ def resultTest () =
58
+ println(" resultTest" )
59
+ assert(sumRoots(List (" 1" , " 4" , " 9" )) == Ok (6 ))
60
+ assert(sumRoots(List (" 1" , " -2" , " 4" )) == Err (s " cannot take sqrt of negative -2.0 " ))
61
+ assert(sumRoots(List ()) == Err (" list is empty" ))
62
+ assert(sumRoots(List (" 1" , " 3ab" )) == Err (" java.lang.NumberFormatException: For input string: \" 3ab\" " ))
63
+
64
+ @ main def Test =
65
+ breakTest()
66
+ optTest()
67
+ resultTest()
0 commit comments