模式匹配列表中任意位置特定元素的最佳方式是什么?

What's the best way to pattern match a specific element at any position in a list?

假设我有一些列表

["a"; "b"; "d"] ["a"; "c"; "d"]

元素可以按任何顺序排列。列表将包含 "b""c" 之一,但绝不会包含两者。

如果 "b" 在列表中,我想 return 一个特定的值,或者如果 "c" 在列表中,我想要一个不同的值。

我是 OCaml 的新手,但据我所知这是不可能通过模式匹配实现的,还是我错过了什么?

执行此操作最惯用的方法是什么?

如果我没理解错的话,你会得到一个未知列表,你知道它包含 "b""c",但不是两者,你想确定是哪种情况。甚至可能找到第一次出现的位置?

这是一个有趣的问题。首先你当然可以手写循环:

let rec find_b_or_c i = function
| []                    -> raise Not_found (* assumed not to happen ? *)
| (("b"|"c") as x) :: _ -> (i, x)
| _ :: xs               -> find_b_or_c (i+1) xs
in
let (i, x) = find_b_or_c 0 my_list in
(* … do something with the index and/or the letter
     (for instance test whether x = "b") … *)

那么问题是结合已有的功能能不能写得更简洁/优雅。如果您对索引不感兴趣,您可以简单地使用 List.find 或其变体 return 一个选项:

let x = List.find (fun x -> x = "b" || x = "c") my_list in (* … *)

您还可以测试 "b"List.mem 的成员资格(或更普遍的 List.exists);然而,使用这种方法,一旦列表包含 "c"(有一个很长的列表,开头有 "c" 但没有 "b",搜索就不会被短路,你会浪费很多时间)。

但是,没有办法用the standard functions获取索引,因为其中none个return个索引。这是故意的,因为列表索引很慢(线性时间),你不应该这样做。如果你真的想要索引,你必须使用上面的手动递归,或者写一个更通用的函数 find_with_index.