let rec add_lists (xs : float list) (ys : float list): float list option =
match xs, ys with
| [], [] -> None
| x :: xs, [] -> None
| [], y :: ys -> None
| x :: xs, y :: ys -> (x +. y) :: add_lists xs ys
问题要求我们将两个列表的元素相加,如果它们的长度不同则返回 None。我尝试了这段代码,但收到一条错误消息:“此变体表达式应具有类型 float 列表选项。类型选项内没有构造函数 ::” 有什么办法可以解决吗?谢谢
那么,如果两者都是空列表,那么它们的长度真的不同吗?不。所以你应该回来
Some []
。
let rec add_lists (xs : float list) (ys : float list): float list option =
match xs, ys with
| [], [] -> Some []
接下来的两个模式是有意义的,但由于您不使用
x
或 xs
,因此可以简化它们。
let rec add_lists (xs : float list) (ys : float list): float list option =
match xs, ys with
| [], [] -> Some []
| _, [] | [], _ -> None
您的最终案例需要返回一个选项类型。事实上,您的尝试没有这样做,这就是您错误的根源。
使用的构造函数(
None
或Some
)将取决于递归的结果。模式匹配可用于确定是否生成 None
或 Some lst
。在前一种情况下,我们知道我们想要返回None
,但在后一种情况下,我们可以将加法结果附加到递归结果的前面。
let rec add_lists (xs : float list) (ys : float list): float list option =
match xs, ys with
| [], [] -> Some []
| _, [] | [], _ -> None
| x::xs, y::ys ->
match add_lists xs ys with
| None -> None
| Some lst -> Some (x +. y :: lst)
如果我们想变得聪明,我们可以意识到选项类型的这种行为是可以概括的,我们甚至可以给它一个操作符名称。
let (>>>) opt f =
match opt with
| None -> None
| Some x -> Some (f x)
我们还可以意识到,当一个列表但不是两个列表都为空时,我们直接返回
None
。如果我们匹配两者都为空,并且两者都不为空,则默认选项只有一个为空。因此,如果我们重新排序模式,代码就会进一步简化。
现在我们可以写:
let rec add_lists (xs : float list) (ys : float list): float list option =
match xs, ys with
| [], [] -> Some []
| x::xs, y::ys -> add_lists xs ys >>> List.cons (x +. y)
| _ -> None
List.map2
来在不等长度的列表上提高 Invalid_argument
。
let add_lists xs ys =
try Some (List.map2 (+.) xs ys)
with Invalid_argument _ -> None