在 OCaml 中将两个列表添加在一起

问题描述 投票:0回答:1
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 列表选项。类型选项内没有构造函数 ::” 有什么办法可以解决吗?谢谢

ocaml
1个回答
1
投票

那么,如果两者都是空列表,那么它们的长度真的不同吗?不。所以你应该回来

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
© www.soinside.com 2019 - 2024. All rights reserved.