为什么我不能将这两个列表传递到OCaml的递归函数中?

时间:2019-07-06 20:32:55

标签: ocaml

我试图在OCaml中编写一个更简单的解析器,但是遇到了我无法逾越的问题。我已将代码简化为最少的示例,这给了我相同的错误:

我想在OCaml中编写一个函数,该函数接受一个整数列表并输出一个字符串列表。 规则是,如果连续有两个1,则输出"eleven";如果只有一个1,则输出"one" 对于其他任何数字,它输出"other"。这段python代码可以完成这项工作:

def convert(numbers, names):
    if len(numbers) == 0:
      return names
    n = numbers.pop(0)
    if n == 1:
        if len(numbers) > 0 and numbers[0] == 1:
            numbers.pop(0)
            names.append("eleven")
        else:
            names.append("one")
    else:
        names.append("other")
    return convert(numbers, names)

convert([1, 1, 2, 1, 3, 1], [])
# -> ['eleven', 'other', 'one', 'other', 'one']

我在OCaml中的尝试是这样的:

let rec convert (numbers : int list) (names : string list) = function
  | [] -> List.rev names
  | 1 :: 1 :: t -> convert t ("eleven" :: names)
  | 1 :: t -> convert t ("one" :: names)
  | _ :: t -> convert t ("other" :: names)
;;

convert [1; 1; 2; 3] [];;

我认为将要发生的是convert会递归地调用自身:整数列表将变小而列表 更大的字符串,直到没有剩余的整数了:

convert [1; 1; 2; 1; 3; 1] []
-> convert [2; 1; 3; 1] ["eleven"]
  -> convert [1; 3; 1] ["other"; "eleven"]
    -> convert [3; 1] ["one"; "other"; "eleven"]
      -> convert [1] ["other"; "one"; "other"; "eleven"]
        -> convert [] ["one"; "other"; "one"; "other"; "eleven"]
          -> ["eleven"; "other"; "one"; "other"; "one"]

但是实际发生的是编译错误:

Error: This expression has type int list -> string list
       but an expression was expected of type string list

突出显示文本convert t ("eleven" :: names)

这是怎么回事?我不明白为什么这行不通。

1 个答案:

答案 0 :(得分:5)

function | ...实际上是fun x -> match x with | ...的简写。那就是:

let convert numbers names = function
  | ...

等同于

let convert numbers names something_else =
  match something_else with
  | ...

您的convert函数因此需要三个参数,并且convert t ("eleven" :: names)返回一个函数int list -> string list而不是从第一个分支推断的string list

function替换为match numbers with以使其编译:

let rec convert (numbers : int list) (names : string list) =
  match numbers with
  | [] -> List.rev names
  | 1 :: 1 :: t -> convert t ("eleven" :: names)
  | 1 :: t -> convert t ("one" :: names)
  | _ :: t -> convert t ("other" :: names)
;;

convert [1; 1; 2; 3] [];;