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中,编码器必须自己声明,如上面的例子。如果两次问同一问题,请交叉链接,以避免重复工作。看起来相同的问题是在中问的,如果两次问同一问题,请交叉链接,以避免重复工作。