查找int列表的不同元素

时间:2017-08-26 21:54:20

标签: pattern-matching ocaml typechecking

我还是OCaml的新手,想要编写一个函数来查找字母表,或者int列表的不同个别编号,并将它们作为列表返回。 我想出了以下内容:

let rec find_alpha (list: int list) (acc: int list) =
   match list with
   |[]       -> acc
   |hd       -> if List.mem hd acc then acc else hd::acc
   |hd::tl   -> if List.mem hd acc then find_alpha tl acc else find_alpha tl hd::acc

编译器说:

|hd       -> if List.mem hd acc then acc else hd::acc
                            ^^^
Error: This expression has type int list but an expression was expected of type int list list
Type int is not compatible with type int list.

即使消息非常明确,我也无法弄清楚为什么会出现类型为int list list的表达式。 我检查hd元素是否已经在acc列表中。如果是,我会将acc作为我的结果返回,如果它不在acc我附加并返回它。

为什么期待int list list

我忘了说,第一个案例[]不应该可以访问,但我仍然包括它,因为我不知道是什么原因。我不应该把它剪掉吗?

2 个答案:

答案 0 :(得分:2)

在模式匹配的第二行中,使用hd作为模式。此模式匹配任何值并将其称为hd。这会使hd成为行中的int list

|hd       -> if List.mem hd acc then acc else hd::acc

当编译器对List.mem的调用进行类型检查时,它会首先分析第一个参数。由于编译器此时已经知道hd具有类型int list,因此由于int list list的类型,它推断第二个参数必须具有类型List.mem(这是'a -> 'a list -> bool,其中'a实例化为int list。如果函数List.hd以相反的顺序获取其参数或编译器类型检查函数以相反的顺序调用,则投诉可能是hd具有类型int list但是与输入int

我不确定你对这条线的意思。列表要么是空的,要么是头部和尾部。 (我不知道为什么你认为“第一种情况[]不应该是可以访问的”;列表肯定是空的。)列表上通常的模式匹配是

match list with
| []       -> …
| hd::tl   -> …

在你的情况下,你不需要任何更复杂的东西。您可以将现有案例纳入[]hd::tl。还有一件事要纠正:你需要在递归调用find_alpha tl (hd::acc)中加上括号,因为find_alpha tl hd::acc被解析为(find_alpha tl hd)::acc

let rec find_alpha (list: int list) (acc: int list) =
   match list with
   |[]       -> acc
   |hd::tl   -> if List.mem hd acc then find_alpha tl acc else find_alpha tl (hd::acc)

由于hd::tl情况的唯一变化是在传递给递归调用的第二个参数中,我不想重复递归调用。此外,函数不依赖于参数的类型,所以我会让它们保持多态。

let rec find_alpha list acc =
   match list with
   | [] -> acc
   | hd::tl -> find_alpha tl (if List.mem hd acc then acc else hd::acc)

如果定义一个中间变量,代码可以说更具可读性。

let rec find_alpha list acc =
   match list with
   | [] -> acc
   | hd::tl ->
     let acc' = if List.mem hd acc then acc else hd::acc in
     find_alpha tl acc'

答案 1 :(得分:1)

| hd -> if List.mem hd acc then acc else hd::acc

这种情况意味着“匹配整个列表并将其命名为hd以下”与

进行比较
| [hd] -> if List.mem hd acc then acc else hd::acc

表示“匹配只包含一个元素的列表并将其命名为hd

特别是

| hd -> if List.mem hd acc then acc else hd::acc

List.mem hd acc正在检查int hd列表是否属于列表acc。这只有在acc是int列表的列表时才有意义。但是,您确定acc是int的列表;产生你看到的编译器错误。