Почему я не могу передать эти два списка в рекурсивную функцию в OCaml? - PullRequest
1 голос
/ 06 июля 2019

Я пытаюсь написать более простой парсер в 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 Ответ

5 голосов
/ 06 июля 2019

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] [];;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...