3.11 option
3.11.1 The Option Datatype
Option implements a functional programming idiom that is often used when a function may or may not return a valid or meaningful value. If there is no return value, then none is returned. If there is a meaningful return value, the value is wrapped in the some variant.
Some Pyret library functions return Option values, such as string-to-number. In this case, if the string is not a valid numeric value, none is returned; otherwise, the numeric value is wrapped in some. A cases expression can be used to evaluate both Option response variants.
fun set-angle(s :: String) -> Number: doc: "If s is not a numeric string, default to 0." cases(Option) string-to-number(s): | some(a) => a | none => 0 end where: set-angle("90") is 90 set-angle("") is 0 set-angle("x") is 0 end
In an contrasting example, the string-index-of function does not provide an Option return value, but instead returns a Number which is either a valid index Number or -1 if the string is not found.
fun find-smiley(s :: String) -> String: i = string-index-of(s, "😊") ask: | i == -1 then: "No smiley!" | otherwise: string-append("Smiley at ", num-to-string(i)) end where: find-smiley("abcd") is "No smiley!" find-smiley("a😊cd") is "Smiley at 1" end
If you wanted to create a version of find-smiley that returned an Option value, it might look like this:
fun option-smiley(s :: String) -> Option: i = string-index-of(s, "😊") ask: | i == -1 then: none | otherwise: some(i) end where: option-smiley("abcd") is none option-smiley("a😊cd") is some(1) end
3.11.2 Option Methods
For none, returns none. For some, applies f to the value field and returns a new some with the updated value.
check: add1 = lam(n): n + 1 end n = none n.and-then(add1) is none s = some(5) s.and-then(add1) is some(6) end
For none, returns v. For some, returns the value field. Useful for providing default values.
check: n = none n.or-else(42) is 42 s = some(5) s.or-else(10) is 5 end
Our example above of set-angle, which defaults to 0, could be replaced with:
check: string-to-number("90").or-else(0) is 90 string-to-number("x").or-else(0) is 0 end