Why there is a plus sign before this type?

后端 未结 2 2029
伪装坚强ぢ
伪装坚强ぢ 2020-12-30 04:15

I was browsing ocaml\'s standard library, and came across this code in the map.ml file.

module type S =
  sig
    type key
    type +\'a t
    val empty: \'a         


        
相关标签:
2条回答
  • 2020-12-30 05:03

    This marks the type as covariant with respect to the module type. Assume you have two maps whose keys are the same type. This + says if the values of one map A are of a subtype of the values of the other map B, then the overall type of map A is a subtype of map B's type. I found a pretty good description of this in the Jane Street blog.

    0 讨论(0)
  • 2020-12-30 05:07

    To build up on Jeffrey's answer, the reason the developers did the work of marking the abstract type as covariant here is likely not to help you use subtyping (essentially nobody uses subtyping in OCaml, as parametric polymorphis is generally preferred), but to use an even-less-well-known aspect of the type system called the "relaxed value restriction", thanks to which covariant abstract types allow more polymorphism.

    You may safely ignore those subtleties until, someday, you hit a problem with an abstract type of yours that is not as polymorphic as you would like, and then you should remember than a covariance annotation in the signature may help.

    We discussed this on reddit/ocaml a few months ago:

    Consider the following code example:

    module type S = sig
      type 'a collection
      val empty : unit -> 'a collection
    end
    
    module C : S = struct
      type 'a collection =
        | Nil
        | Cons of 'a * 'a collection
      let empty () = Nil
    end
    
    let test = C.empty ()
    

    The type you get for test is '_a C.collection, instead of the 'a C.collection that you would expect. It is not a polymorphic type ('_a is a monomorphic inference variable that is not yet fully determined), and you won't be happy with it in most cases.

    This is because C.empty () is not a value, so its type is not generalized (~ made polymorphic). To benefit from the relaxed value restriction, you have to mark the abstract type 'a collection covariant:

    module type S = sig
      type +'a collection
      val empty : unit -> 'a collection
    end
    

    Of course this only happens because the module C is sealed with the signature S : module C : S = .... If the module C was not given an explicit signature, the type-system would infer the most general variance (here covariance) and one wouldn't notice that.

    Programming against an abstract interface is often useful (when defining a functor, or enforcing a phantom type discipline, or writing modular programs) so this sort of situation definitely happens and it is then useful to know about the relaxed value restriction.

    If you want to understand the theory, the value restriction and its relaxation are discussed in the 2004 research article Relaxing the value restriction from Jacques Garrigue, whose first few page are a rather interesting and accessible introduction to the topic and main idea.

    0 讨论(0)
提交回复
热议问题