ocaml:为什么特定类型不匹配';签名

ocaml:为什么特定类型不匹配';签名,ocaml,Ocaml,我是一个初学者,我正在努力理解我做错了什么。感谢您的指导。我有签名 val input : arpv4:('a -> unit Lwt.t) -> ipv4:('a -> unit Lwt.t) -> ipv6:('a -> unit Lwt.t) -> ?decode:(Mirage_protocols.Ethernet.proto ->

我是一个初学者,我正在努力理解我做错了什么。感谢您的指导。我有签名

val input :
           arpv4:('a -> unit Lwt.t) ->
           ipv4:('a -> unit Lwt.t) ->
           ipv6:('a -> unit Lwt.t) ->
           ?decode:(Mirage_protocols.Ethernet.proto ->
                   Cstruct.t -> Mirage_protocols.Ethernet.proto * 'a) ->
           t -> Cstruct.t -> unit Lwt.t
目标是通用,并将实现推迟到参数函数。如果我使用类型
Cstruct.t
实现表达式,例如

...
   decode:(fun proto payload -> (proto, payload))
我得到了错误

     Values do not match:
         val input :
           arpv4:(Cstruct.t -> unit Lwt.t) ->
           ipv4:(Cstruct.t -> unit Lwt.t) ->
           ipv6:(Cstruct.t -> unit Lwt.t) ->
           ?decode:(Mirage_protocols.Ethernet.proto ->
                   Cstruct.t -> Mirage_protocols.Ethernet.proto * Cstruct.t) ->
           t -> Cstruct.t -> unit Lwt.t
       is not included in
         val input :
           arpv4:('a -> unit Lwt.t) ->
           ipv4:('a -> unit Lwt.t) ->
           ipv6:('a -> unit Lwt.t) ->
           ?decode:(Mirage_protocols.Ethernet.proto ->
                   Cstruct.t -> Mirage_protocols.Ethernet.proto * 'a) ->
           t -> Cstruct.t -> unit Lwt.t

我不明白为什么
Cstruct.t
不匹配
'a
。我做错了什么

'a
出现在箭头的左侧时,表示函数接受任何类型。也就是说,函数必须是多态的。这并不意味着函数可以接受任何单一类型,而是意味着函数必须接受所有可能的类型。

'a
出现在箭头的左侧时,表示函数可以接受任何类型。也就是说,函数必须是多态的。这并不意味着函数可以接受任何单一类型,而是意味着函数必须接受所有可能的类型。

如前所述,在ocaml中,类型变量'a',b等代表“所有类型,由编译器推断”。最简单的情况是identity函数(只返回其参数的函数),它可以接受并返回任何类型,因此其参数和返回类型可以用类型变量“a”表示。或者,列表或数组可以包含任何类型,因此返回列表或数组的函数可能具有“列表”或“数组”类型

但许多问题无法“针对所有类型”解决,即编写的代码特定于一个或多个特定类型。如上所述,标识函数可以接受并返回任何类型。但是,例如,一个将参数乘以2并返回乘积的函数必须接受并返回一个数字,可以是int,也可以是float。此外,在ocaml中,有单独的运算符用于整数和浮点的乘法:因此,如果您希望有一个同时适用于整数和浮点的函数,您可能希望使用一个数字变量并与之匹配,在这种情况下,您不需要依赖模块级多态性-代码在变量类型上是单态的

但在这种情况下,您可能不希望函数接受和/或返回变量。您可能希望为int和float提供单独的实现,并显式调用适当的版本。您可以通过模块接口和模块实现来实现这一点。函子在实现这一点时非常有用,可以作为手工写出专门模块的简写

你在上个月问了同样的问题。这里提供了一个使用共享约束的模块级多态性示例:

module type Printable = sig
  type t
  val say : t -> unit
end

module Int_print: Printable with type t := int = struct
  let say i = Printf.printf "%d\n" i
end

module String_print: Printable with type t := string = struct
  let say s = Printf.printf "%s\n" s
end

let () =
  let open Int_print in
  say 20 ;
  let open String_print in
  say "hello again"

OcAML没有“ad hoc”多态性,编译器将选择哪一种用户提供的替代品应在任何特定情况下应用(在C++和类似语言中称为“函数重载”):在OCAML中,编码器必须自己声明,如上面的例子。在ocaml中,类型变量“a”、“b”等代表“所有类型,由编译器推断”。最简单的情况是identity函数(只返回其参数的函数),它可以接受并返回任何类型,因此其参数和返回类型可以用类型变量“a”表示。或者,列表或数组可以包含任何类型,因此返回列表或数组的函数可能具有“列表”或“数组”类型

但许多问题无法“针对所有类型”解决,即编写的代码特定于一个或多个特定类型。如上所述,标识函数可以接受并返回任何类型。但是,例如,一个将参数乘以2并返回乘积的函数必须接受并返回一个数字,可以是int,也可以是float。此外,在ocaml中,有单独的运算符用于整数和浮点的乘法:因此,如果您希望有一个同时适用于整数和浮点的函数,您可能希望使用一个数字变量并与之匹配,在这种情况下,您不需要依赖模块级多态性-代码在变量类型上是单态的

但在这种情况下,您可能不希望函数接受和/或返回变量。您可能希望为int和float提供单独的实现,并显式调用适当的版本。您可以通过模块接口和模块实现来实现这一点。函子在实现这一点时非常有用,可以作为手工写出专门模块的简写

你在上个月问了同样的问题。这里提供了一个使用共享约束的模块级多态性示例:

module type Printable = sig
  type t
  val say : t -> unit
end

module Int_print: Printable with type t := int = struct
  let say i = Printf.printf "%d\n" i
end

module String_print: Printable with type t := string = struct
  let say s = Printf.printf "%s\n" s
end

let () =
  let open Int_print in
  say 20 ;
  let open String_print in
  say "hello again"

OcAML没有“ad hoc”多态性,编译器将选择哪一种用户提供的替代品应在任何特定情况下应用(称为“C++中的函数重载”和类似的语言):在OCAML中,编码器必须自己声明,如上面的例子。如果两次问同一问题,请交叉链接,以避免重复工作。看起来相同的问题是在中问的,如果两次问同一问题,请交叉链接,以避免重复工作。