OCAML 函数要求我返回单位而不是"列表"



我最近开始使用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

当我调用该函数时,它运行得很好,但它的运行与预期的一样,但让我困扰的是错误消息。知道为什么会出现吗?

附言:我使用Emacs-图阿雷格模式作为文本编辑器和编译器。

if/else句法结构是一个表达式。整个表达式的类型由分支返回的表达式类型定义。显然,它们必须是同一类型的。如果没有指定else分支,则假定省略的else分支是类型unit的表达式,基本上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

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

随着你对OCaml习惯用法越来越熟悉,这些解决方案就会自然而然地出现。

最新更新