我最近开始用ocaml编写代码,这种编程语言在定义我希望返回的函数时是非常明智的。我想要编写一个函数,它使用两个列表作为参数(假定按升序排列,并带有int类型的元素),并返回一个列表,其中包含前两个列表的所有元素,也是按升序排列的。
以下是我所取得的成就:
let inter l1 l2 =
let rec aux l1 l2 l3=
if List.hd l1<List.hd l2 then aux (List.tl l1) l2 (List.hd l1 :: l3)
else (if List.hd l1>List.hd l2 then aux l1 (List.tl l2) (List.hd l2::l3)
else (if l1 = [] then List.fold_left (fun x y -> y::x) l3 l2
else if l2=[] then List.fold_left (fun x y -> y::x) l3 l1
))
in List.rev (aux l1 l2 []);;但是,当我编译它时,它会返回以下错误消息:
Error: This expression has type 'a list
but an expression was expected of type unit当我调用该函数时,它运行得很好,但它的工作方式与预期的一样,但困扰我的是错误消息。知道为什么会出现吗?
PS:我使用Emacs模式作为文本编辑器和编译器。
发布于 2016-10-14 19:00:15
Th if/else句法结构是一种表达式。整个表达式的类型由分支返回的表达式类型定义。显然,它们必须是同一类型的。如果您没有指定else分支,则假定省略的else分支是类型单元的表达式,基本上if c then e是if c then e else ()的缩写。
这句话:
if l2=[] then List.fold_left (fun x y -> y::x) l3 l1实际上是以下词的缩写:
if l2=[] then List.fold_left (fun x y -> y::x) l3 l1 else ()因此,OCaml试图将List.fold_left (fun x y -> y::x) l3 l1与()统一起来。他们肯定有不同的类型。如果您添加了一个显式的else分支,那么所有内容都会进行类型检查(不确定正确性):
let inter l1 l2 =
let rec aux l1 l2 l3=
if List.hd l1<List.hd l2 then aux (List.tl l1) l2 (List.hd l1 :: l3)
else (if List.hd l1>List.hd l2 then aux l1 (List.tl l2) (List.hd l2::l3)
else (if l1 = [] then List.fold_left (fun x y -> y::x) l3 l2
else if l2=[] then List.fold_left (fun x y -> y::x) l3 l1 else []
))
in List.rev (aux l1 l2 []);;您的沮丧可能是因为您对类似C的编程语言感到满意。当试图在OCaml中强制使用C编程风格时,它可能会令人沮丧。模式匹配是OCaml的一个非常强大的特性,可以简化您的解决方案:
let rec inter l1 l2 =
match l1, l2 with
| [], _ -> l2
| _, [] -> l1
| (h1 :: t1), (h2 :: t2) ->
if h1 <= h2 then
h1 :: inter t1 l2
else
h2 :: inter l1 t2第一个模式是“如果l1是空列表,那么返回l2”。第二种模式是“如果l2是空列表,则返回l1”。当测试模式三时,我们知道这两个列表都不是空的,因此我们可以对它们的内容进行模式匹配,因此不需要使用list.hd等。我们使用if-语句来确定哪个头变成了新的头,而我们在递归时使用的是哪个尾。
当您更加熟悉OCaml成语时,这些解决方案将自然而然地提供给您。
https://stackoverflow.com/questions/40050059
复制相似问题