递归函数中的OCaml语法错误

时间:2014-02-03 21:34:06

标签: recursion ocaml

我正在编写一个带有一对列表的函数,如果两个列表的长度相等,那么从每个列表中创建一对每个元素,但我的函数不起作用,编译器说有一个语法错误

有人可以解释为什么函数末尾的分号会出现语法错误吗?

这是我的代码:

let define_tuple a b =
(a, b);;

let zip (a, b) =
if List.length (fst (a, b)) != List.length (fst (a, b)) 
then
printf_string "lengths of 2 lists need to be equal"
else
let rec create_tuples (a, b) = 
if List.length (List.tl (fst (a, b))) = 0 && List.length (List.tl (snd (a, b))) != 0
then 
[]
else
List.append define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b))) create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)));;



zip ([1; 2; 3], [2; 3; 4]);;

2 个答案:

答案 0 :(得分:2)

您的代码中存在相当多的可能改进和错误,我将其列在以下所有内容中:

否。 1

如果您在一个文件中编写代码并尝试编译/运行您的文件,那么您最终不需要;;来为每个函数。

否。 2

let define_tuple a b = (a, b);;

您无需定义此类功能,而是可以直接使用(a, b)

否。 3

let zip (a, b) =
  if List.length (fst (a, b)) != List.length (fst (a, b)) then
    printf_string "lengths of 2 lists need to be equal"
  else
    let rec create_tuples (a, b) = 
      if List.length (List.tl (fst (a, b))) = 0 && List.length (List.tl (snd (a, b))) != 0
      then 
    []
      else
    List.append define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b))) create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)));;

<强> 3.1

对于您的第一个if ... else ...,它不正确,因为if分支返回unit并且else分支返回list

在OCaml中,ifelse或模式匹配的任何分支都应返回相同的类型。

<强> 3.2

由于 3.1 ,我建议你为non-equal lengths案例写一个例外。通过这种方式,整个函数仍然返回列表,代码更具可读性,函数用户也可以“抓住”您的异常情况。

<强> 3.3

表示函数create_tuples

let rec create_tuples (a, b) = 
      if List.length (List.tl (fst (a, b))) = 0 && List.length (List.tl (snd (a, b))) != 0
      then 
    []
      else
    List.append define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b))) create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)));;

<强> 3.3.1

List.length (List.tl (fst (a, b))) = 0

您不需要使用fst (a,b),只需a即可,因为a已经知道。

snd用法相同。

基本上,您的代码不需要fstsnd

<强> 3.3.1.1

您应该检查ab的长度是否为0,而不是tl

<强> 3.3.2

您也不需要(a,b)元组作为create_tuples的参数,而是可以使用create_tuples a b。它更好,因为您的代码不需要为一对参数创建元组。

<强> 3.3.3

List.append define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b))) create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b)))

首先,List.append是将一个列表附加到另一个列表。在您的情况下,您要在列表中添加元素,因此您应该使用::

如果要使用函数应用程序的值,则应使用()包含函数应用程序。

例如,你应该(define_tuple (List.hd (fst (a, b))) (List.hd (snd (a, b)))):: (create_tuples (List.tl (fst (a, b)), List.tl (snd (a, b))))

如果你一起考虑以前的观点,你可以做到

(List.hd a, List.hd b)::(create_tuples (List.tl a) (List.tl b))

<强> 3.4

您已定义了函数create_tuples,但您是否真的在代码中使用它?否。

所以最后,你应该做

in create_tuples a b

否。 4

您应该使用<>来检查不平等。


完整的细化/更正代码

exception Non_equal_list_length

let zip a b =
  if List.length a <> List.length b then raise Non_equal_list_length
  else
    let rec create_tuples a b = 
      if List.length a = 0 && List.length b = 0 then []
      else (List.hd a, List.hd b)::(create_tuples (List.tl a) (List.tl b))
    in
    create_tuples a b

进一步改进:

  • 您可以直接在列表上使用模式匹配
  • 你应该总是考虑尾递归

最终改进的代码:

exception Non_equal_list_length

let zip a b =
    let rec zipping acc = function
      | [], [] -> List.rev acc
      | hd1::tl1, hd2::tl2 -> zipping ((hd1,hd2)::acc) (tl1,tl2)
      | _ -> raise Non_equal_list_length
    in
    zipping [] (a,b)

答案 1 :(得分:1)

表达式let a = b仅在模块的最顶层有效,它定义了从模块导出的名称。在其他任何地方,此表达式用于引入局部变量(或变量),其形式为let a = b in c。您错过了in关键字以及您希望使用本地变量create_tuples的表达式。

(按顺序获取语法时会发现一些其他错误。)

<强>更新

这是一个使用用let a = b in c声明的辅助函数的函数的简单示例:

let myrev l =
    let rec irev sofar = function
    | [] -> sofar
    | hd :: tl -> irev (hd :: sofar) tl
    in
    irev [] l