【问题标题】:ocaml: why does specific type mismatch 'a signatureocaml:为什么特定类型不匹配'签名
【发布时间】:2020-04-14 22:00:11
【问题描述】:

我是一个初学者,我很难理解我做错了什么。感谢所有指导。我有签名

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。我做错了什么?

【问题讨论】:

标签: ocaml


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

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

    但在这种情况下,您可能不希望函数获取和/或返回变体。您可能希望为整数和浮点数提供单独的实现,并显式调用适当的版本。您可以使用模块接口和模块实现来做到这一点。函子在实现这一点时很有用,作为手动编写专门模块的简写。

    您在https://discuss.ocaml.org/t/why-doesnt-a-specific-type-fulfill-a/5525/6 提出了同样的问题。那里已经为您提供了一个在模块级别使用共享约束的多态性示例:

    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 中coder 必须自己说明这一点,如上例所示。

    【讨论】:

      猜你喜欢
      • 2019-03-27
      • 2019-12-04
      • 2015-05-28
      • 2021-07-20
      • 1970-01-01
      • 2017-10-05
      • 2012-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多