签名声明在编译时更改

Signature declaration changed on compilation

当我尝试编译我的代码时,出现以下错误

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 listint liststring liststring list 等等,不像更通用的实现能够映射 int liststring list.

要纠正该问题,您需要仔细检查您的实施。确保您没有分支指令(如 if/then/else、匹配),这样一个分支 returns 输入列表的一个或多个元素,另一个分支 returns 一个或多个元素的输出列表。为了证明这一点,请考虑以下实现,

let rec filter_map f = function
  | [] -> []
  | x :: xs -> match f x with
    | None -> xs
    | Some x -> x :: filter_map f xs

这里我犯了一个错误,当 f x 的计算结果为 None 时,返回了输入列表 xs。另一个分支,构建输出列表,所以我们统一了输入和输出列表的类型。在正确的实现中,你应该在两个分支中递归调用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