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