实现一个程序,它接受一个字符串和一个列表,如果没有找到任何匹配项,则返回 NONE,如果找到则返回不包含该元素的列表。
all_except_option ("string",["he","she","string"]) = SOME ["he","she"]
SOME [] 与 NONE 有何不同?例如,如果此函数只返回一个列表,则可以说删除 "string" 的出现不会导致其他字符串:列表已经为空,或者它仅包含 "string" 的出现。我不确定为什么 NONE 与 SOME [] 在一种情况下比另一种情况下得到保证。
所以更好的函数是简单地返回一个简单的列表:
fun except (x, ys) = List.filter (fn y => x <> y)
什么时候返回'一个选项有用?
例如当返回类型没有办法表明没有结果时:
fun lookup k1 [] = NONE
| lookup k1 ((k2,v)::pairs) =
if k1 = k2
then SOME v
else lookup k1 pairs
这个函数返回 0 或 1 个东西。但它也是一个简单的函数,因为它从不通过递归聚合结果。当递归函数需要解包递归结果时,返回复合数据类型(如'a option)会变得复杂。
一个很好的例子是 eval 函数有时会失败:
datatype expr
= Add of expr * expr
| Sub of expr * expr
| Mul of expr * expr
| Div of expr * expr
| Int of int
fun eval (Int n) = SOME n
| eval (Add (e1, e2)) = evalHelper ( op+ ) (e1, e2)
| eval (Sub (e1, e2)) = evalHelper ( op- ) (e1, e2)
| eval (Mul (e1, e2)) = evalHelper ( op* ) (e1, e2)
| eval (Div (e1, e2)) =
case eval e1 of
NONE => NONE
| SOME x => case eval e2 of
NONE => NONE
| SOME 0 => NONE
| SOME y => SOME (x div y)
and evalHelper binop (e1, e2) =
case eval e1 of
NONE => NONE
| SOME x => case eval e2 of
NONE => NONE
| SOME y => SOME (binop (x, y))
这里的返回类型是int option,这意味着你最常返回一个int,但如果你除以零,就会导致“没有值” ,因此我们不会引发异常,而是返回NONE,这需要我们在有结果时返回SOME n,以便类型适合两种情况。
快速演示:
- eval (Div (Int 5, Int 2));
> val it = SOME 2 : int option
- eval (Div (Int 5, Int 0));
> val it = NONE : int option
- eval (Div (Int 2, Sub (Int 3, Int 3)));
> val it = NONE : int option
- eval (Div (Int 0, Int 1));
> val it = SOME 0 : int option
这里SOME 0其实意思是“结果为0”,和“不能被零除”是不一样的。