Когда я пытаюсь скомпилировать свой код, я получаю следующую ошибку
Error: Signature mismatch:
...
Values do not match:
val filter_map : ('b -> 'b option) -> 'b t -> 'b list
is not included in
val filter_map : ('b -> 'a option) -> 'b t -> 'a list
File "set.ml", line 7, characters 2-55: Expected declaration
File "treeSet.ml", line 105, characters 10-20: Actual declaration
Однако моя подпись на самом деле объявлена следующим образом.
module type SetS = sig
type 'a t
val empty : 'a t
val insert : 'a t -> 'a -> 'a t
val contains : 'a t -> 'a -> bool
val filter_map : ('a -> 'b option) -> 'a t -> 'b list
end
По какой-то причине ошибка, которую я получаю при компиляции, показывает объявление типа, отличное от того, которое я фактически реализовал. Почему это происходит и как я могу это исправить?
Не видя кода, я бы просто прокомментировал, что вы не можете сделать код более полиморфным, чем он есть на самом деле, объявив его таковым. Скорее всего компилятор прав насчет типа :-)
Ошибка Signature mismatch
означает, что производная подпись модуля отличается от указанной подписи. Например, предположим, что мы хотим написать модуль со следующей сигнатурой:
module type Expected = sig
val filter : ('a -> bool) -> 'a list -> 'a list
end
и мы пишем,
module Real : Expected = struct
let filter = List.filter_map
end
Сообщение об ошибке, которое мы получим, будет,
Signature mismatch:
Modules do not match:
sig val filter : 'a list -> f:('a -> 'b option) -> 'b list end
is not included in
Expected
Values do not match:
val filter : 'a list -> f:('a -> 'b option) -> 'b list
is not included in
val filter : ('a -> bool) -> 'a list -> 'a list
Итак, проблема в том, что предложенная нами реализация filter
имеет тип 'a list -> f:('a -> 'b option) -> 'b list
, но то, что мы действительно хотели и ожидали от типа filter
, это ('a -> bool) -> 'a list -> 'a list
. Об этом говорит сообщение об ошибке.
Применительно к вашему случаю ваша реализация имеет предполагаемый тип ('b -> 'b option) -> 'b t -> 'b list
, который не соответствует требуемому типу ('b -> 'a option) -> 'b t -> 'a list
. Обратите внимание, что ваш тип менее общий. Он фильтрует список, не меняя тип элемента. Таким образом, он может фильтровать только карту int list
в int list
, string list
в string list
и так далее, в отличие от более общей реализации, которая может отображать int list
в string list
.
Чтобы устранить проблему, вам необходимо тщательно проверить свою реализацию. Убедитесь, что у вас нет инструкций ветвления (например, if/then/else, match), чтобы одна ветвь возвращала элемент или элементы входного списка, а другая ветвь возвращала элемент или элементы выходного списка. Чтобы продемонстрировать это, рассмотрим следующую реализацию:
let rec filter_map f = function
| [] -> []
| x :: xs -> match f x with
| None -> xs
| Some x -> x :: filter_map f xs
Здесь я сделал ошибку, вернув xs
список ввода, когда f x
оценивается как None
. Другая ветвь строит выходной список, поэтому мы получили унифицированные типы входных и выходных списков. В правильной реализации вы должны рекурсивно вызывать filter_map
в обеих ветвях,
let rec filter_map f = function
| [] -> []
| x :: xs -> match f x with
| None -> filter_map f xs
| Some x -> x :: filter_map f xs
Какова реализация функции? OCaml предполагает, что
'a
и'b
должны быть одинаковыми в зависимости от реализации, поэтому сигнатура, в которой они могут различаться независимо, не допускается. Пожалуйста, отредактируйте вопрос, чтобы показать реализацию, и я буду рад написать ответ, объясняющий, откуда он получает эту информацию.