Декларация подписи изменена при компиляции

Когда я пытаюсь скомпилировать свой код, я получаю следующую ошибку

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

По какой-то причине ошибка, которую я получаю при компиляции, показывает объявление типа, отличное от того, которое я фактически реализовал. Почему это происходит и как я могу это исправить?

Какова реализация функции? OCaml предполагает, что 'a и 'b должны быть одинаковыми в зависимости от реализации, поэтому сигнатура, в которой они могут различаться независимо, не допускается. Пожалуйста, отредактируйте вопрос, чтобы показать реализацию, и я буду рад написать ответ, объясняющий, откуда он получает эту информацию.

Silvio Mayolo 22.04.2022 22:38

Не видя кода, я бы просто прокомментировал, что вы не можете сделать код более полиморфным, чем он есть на самом деле, объявив его таковым. Скорее всего компилятор прав насчет типа :-)

Jeffrey Scofield 22.04.2022 22:38
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
42
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Ошибка 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

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