问题描述
我想使用 List.assoc
实现 List.find
函数,这是我尝试过的:
let rec assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> try (List.find (fun x -> a = x) lista)
b
with Not_found -> assoc l x;;
但它给了我这个错误:
该表达式的类型为 ('a * 'b) 列表,但预期表达式的类型为 'a 列表 类型变量 'a 出现在 'a * 'b
我不知道这是预期发生的事情还是我做错了什么。我也试过这个作为替代:
let assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> match List.split lista with
| (l1,l2) -> let ind = find l1 (List.find (fun s -> compare a x = 0))
in List.nth l2 ind;;
let rec find lst x =
match lst with
| [] -> raise Not_found
| h :: t -> if x = h then 0 else 1 + find t x;;
这段代码的问题是函数的类型应该是('a * 'b) list -> 'a -> 'b,而是(('a list -> 'a) * 'b) list -> ('a list -> 'a) -> 'b,所以当我尝试
assoc [(1,a);(2,b);(3,c)] 2;;
我明白了:
此表达式的类型为 int 但应为类型的表达式 'a list -> 'a(指列表中的一对的第一个元素)
我不明白为什么我没有得到预期的函数类型。
解决方法
首先,关于使您的 assoc
函数更符合 OCaml 习惯的快速建议:让它将列表作为最后一个参数。
其次,您为什么要尝试在查找方面实现这一点?没有它就容易多了。
let rec assoc x lista =
match lista with
| [] -> raise Not_found
| (a,b) :: xs -> if a = x then b else assoc x xs
使用 OCaml 中的列表工作方式,这样的事情更简单、更高效。
将列表作为最后一个参数,甚至意味着我们可以写得更简洁。
let rec assoc x =
function
| [] -> raise Not_found
| (a,b) :: xs -> if a = x then b else assoc x xs
对于您的问题,OCaml 从函数的使用方式推断函数的类型。
find l1 (List.find (fun s -> compare a x = 0))
我们知道 l1 是一个 int 列表。因此,我们必须尝试在 int 列表列表中找到它。所以:
List.find (fun s -> compare a x = 0)
必须返回一个 int list 列表。一团糟。试着重新思考你的函数,你最终会得到更容易推理的东西。