Why doesn't a specific type fulfill 'a

Good day -

I’m struggling and seeking wisdom. I have the signature

...
val input :
           arpv4:('a -> unit Lwt.t) ->
           ipv4:('a -> unit Lwt.t) ->
           ipv6:('a -> unit Lwt.t) ->
           ?decap:(Mirage_protocols.Ethernet.proto ->
                   Cstruct.t -> Mirage_protocols.Ethernet.proto * 'a) ->
           t -> Cstruct.t -> unit Lwt.t

If I let 'a be Cstruct.t, I’ve notified of

Values do not match:
         val input :
           arpv4:(Cstruct.t -> unit Lwt.t) ->
           ipv4:(Cstruct.t -> unit Lwt.t) ->
           ipv6:(Cstruct.t -> unit Lwt.t) ->
           ?decap:(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) ->
           ?decap:(Mirage_protocols.Ethernet.proto ->
                   Cstruct.t -> Mirage_protocols.Ethernet.proto * 'a) ->
           t -> Cstruct.t -> unit Lwt.t

In this example why can’t Cstruct.t be 'a?

Thanks.

In a signature, when you have a value type variable like 'a, you should implicitly read it as if the type begins with "for all types 'a".

So, to consider a simpler example, a signature like

val value_exn : 'a option -> 'a

says that value_exn takes an option containing any type and returns a value of that same type.

A function of type int option -> int doesn’t satisfy that requirement - you can’t, for example, give it a bool option.

I appreciate the response and now understand what I’m doing wrong. My goal is to be generic and defer typing and implementation to the parameter functions. That is, let the parameter functions determine the type. How do I go about this?

Thanks.

That’s hard to say without knowing the implementation. In general I would guess that some part of your code is passing a Cstruct.t to one of arpv4/ipv4/ipv6 and/or using the result of decap as if it contains a Cstruct.t.

Your question does not immediately make a great deal of sense. If you want Cstruct.t to be an abstract type then then have an interface file that makes it so. If you want to pass your functions a number of different possible types and match on them then consider using a variant type. You can make a factory function for first class modules with type deduction using locally abstract types, but that seems well beyond what you have in mind.

By the way, if you want to use modules as a kind of abstract interface that you are going to code to for different types, you can do it with (possibly destructive) sharing constraints. Something like this:

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"

For more see the manual