Вопрос

Я хотел иметь хвостовую рекурсивную версию List.map, поэтому я написал свой собственный.Вот оно:

let rec list_map f l ?(accum=[])=
  match l with
      head :: tail -> list_map f tail ~accum:(head :: accum)
    | [] -> accum;;

Всякий раз, когда я компилирую эту функцию, я получаю:

File "main.ml", line 69, characters 29-31:
Warning X: this optional argument cannot be erased.

В Учебник говорит, что это означает, что я пытаюсь создать функцию без необязательных аргументов.Но приведенная выше функция явно принимает необязательные аргументы.

Наверное, я просто делаю что-то действительно глупое, но что?

Это было полезно?

Решение

Предыдущие решения действительно компилируются, но не дают ожидаемого результата.Функция f никогда не применяется к аргументам.Правильный код - это:

let rec list_map f ?(accum = []) l = match l with
    | head :: tail -> list_map f ~accum:(f head :: accum) tail
    | [] -> accum;;

Предполагаемый тип является:

val list_map : ('a -> 'b) -> ?accum:'b list -> 'a list -> 'b list = <fun>

...в отличие от неправильного:

val list_map : 'a -> ?accum:'b list -> 'b list -> 'b list = <fun>

Пожалуйста, обратите внимание, что список результатов перевернут:

# list_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [16.; 8.; 4.; 2.]

...и равно функции rev_list из модуля списка:

# List.rev_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [16.; 8.; 4.; 2.]

Таким образом, вы можете захотеть изменить свою функцию на:

let rec list_map f ?(accum = []) l = match l with
    | head :: tail -> list_map f ~accum:(f head :: accum) tail
    | [] -> List.rev accum;;

...который также должен быть хвостово-рекурсивным (согласно руководству) и возвращает список в исходном порядке:

# list_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [2.; 4.; 8.; 16.]

Другие советы

Да, ваш необязательный аргумент не может быть последним, потому что, поскольку OCaml поддерживает частичные приложения, функция, в которой отсутствует последний необязательный аргумент, будет просто выглядеть как частично примененная функция, которая все еще ищет необязательный аргумент.Единственный способ сообщить ему, что вы не собираетесь предоставлять необязательный аргумент, - это увидеть, что вы предоставили аргумент после него.

Если вам нужно сделать это в последнюю очередь, вы можете поставить пустышку unit аргумент после этого:

let rec list_map f l ?(accum=[]) () =
  match l with
      head :: tail -> list_map f tail ~accum:(head :: accum) ()
    | [] -> accum;;

Но в этом случае, да, изменение порядка было бы лучше.

Вам нужен необязательный аргумент после необязательный вариант.Просто измените порядок аргументов вашей функции:

let rec list_map f ?(accum=[]) l=
  match l with
    head :: tail -> list_map f  ~accum:(head :: accum) tail
  | [] -> accum;;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top