我还是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
?
我忘了说,第一个案例[]
不应该可以访问,但我仍然包括它,因为我不知道是什么原因。我不应该把它剪掉吗?
答案 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的列表;产生你看到的编译器错误。