ocaml函数要求我返回单位而不是'列表

时间:2016-10-14 18:43:09

标签: ocaml

我最近开始使用ocaml进行编码,在定义我希望函数返回的内容时,这种编程语言绝对是明智的。 我想编写一个函数,它使用2个列表作为参数(应该按升序排列并使用int类型的元素)并返回一个列表,其中包含前2个列表的所有元素,也按升序排列。

这是我到目前为止所取得的成就:

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 - Tuareg Mode作为文本编辑器和编译器。

1 个答案:

答案 0 :(得分:0)

Th if/else句法结构是一个表达式。整个表达式的类型由分支返回的表达式类型定义。显然,它们必须属于同一类型。如果你没有指定else分支,那么假设省略的else分支是单元类型的表达式,基本上if c then eif 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语言编程语言感到满意。尝试在其中强制使用C编程风格时,OCaml会令人沮丧。模式匹配是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

第一个模式表示&#34;如果l1是空列表,则返回l2&#34;。第二种模式说&#34;如果l2是空列表,则返回l1&#34;。测试模式三时,我们知道两个列表都不是空的,因此我们可以对其内容进行模式匹配,因此不需要使用list.hd等。我们使用if语句来确定哪个头部成为新头部以及我们在递归时使用哪个尾部。

随着您对OCaml习语的熟悉,这些解决方案将自然而然地为您服务。