OCaml functors :: counter-intuitive behaviour

前端 未结 4 428
[愿得一人]
[愿得一人] 2021-01-11 11:18

I am experimenting with the module language of OCaml (3.12.1), defining functors and signatures for modules and so on, mostly following the examples from Chapter 2 of the OC

相关标签:
4条回答
  • 2021-01-11 12:02

    If you look at the inferred signature when you don't write something explicitly:

    # module IntType = struct type t = int end ;;
    module IntType : sig type t = int end
    

    The signature exposes that t is an int. Your signature, on the contrary:

    # module IntType : SOMETYPE = struct type t = int end ;;
    module IntType : SOMETYPE
    

    is really:

    # module IntType : sig type t end = struct type t = int end ;;
    module IntType : sig type t end
    

    This seems to solve your problem:

    # module IntType : (SOMETYPE with type t = int) = struct type t = int end ;;
    module IntType : sig type t = int end
    # module IdentityInt = Identity(IntType) ;;
    module IdentityInt : sig val f : IntType.t -> IntType.t end
    # IdentityInt.f 0 ;;
    - : IntType.t = 0
    

    (you don't need the parens, but they help mentally parse). Basically, you expose the fact that t is an int with your signature. So that OCaml knows the equality IntType.t = int.

    For more details of the internals, I'll leave it to more knowledgeable people.

    0 讨论(0)
  • 2021-01-11 12:13

    Your key error was here:

    module IntType : SOMETYPE = struct type t end ;;

    When you ascribe the signature SOMETYPE, it's an opaque ascription, and the identity with int is lost. Type IntType.t is now an abstract type.

    You need instead to ascribe the signature SOMETYPE with type t = int.

    This transcript shows the difference:

    # module type SOMETYPE = sig type t end;;
    module type SOMETYPE = sig type t end
    # module IntType : SOMETYPE with type t = int = struct type t = int end;; 
    module IntType : sig type t = int end
    # module AbsType : SOMETYPE = struct type t = int end;;                 
    module AbsType : SOMETYPE
    

    The language-design issues around modules and ascription are well covered in the lead designer's 1994 paper on modules, types, and separate compilation. The hairy math parts can all be skipped.

    0 讨论(0)
  • 2021-01-11 12:14

    When you write:

    module IntType : SOMETYPE = struct type t = int end ;;
    

    You are constraining the signature of InType to be exactly SOMETYPE. This means, for instance, that the type t is now becoming an abstract type (whose implementation is unknown to the typer).

    So IdentityInt.f type is still IntType.t -> IntType.t, but, by using a signature constraint, you've explicitly removed the equation IntType.t = int from the typer knowledge. The error message you get tells you exactly that.

    0 讨论(0)
  • 2021-01-11 12:15

    The : construct is different in the core language and in the module language. In the core language, it is an annotation construct. For example, ((3, x) : 'a * 'a list) constrains the expression to have some type that is an instance of 'a * 'a list; since the first element of the pair is an integer, let (a, b) = ((3, x) : 'a * 'a list) in a + 1 is well-typed. The : construct on modules does not mean this.

    The construct M : S seals the module M to the signature S. This is an opaque seal: only the information given in the signature S remains available when typing uses of M : S. When you write module IntType : SOMETYPE = struct type t end, this is an alternate syntax for

    module IntType = (struct type t end : SOMETYPE)
    

    Since the type field t in SOMETYPE is left unspecified, IntType has an abstract type field t: the type IntType is a new type, generated by this definition.

    By the way, you probably meant module IntType = (struct type t = int end : SOMETYPE); but either way, IntType.t is an abstract type.

    If you want to specify that a module has a certain signature while leaving some types exposed, you need to add an explicit equality for these types. There's no construct to add all inferable equalities, because applying a signature to a module is usually meant for information hiding. In the interest of simplicity, the language only provides this one generative sealing construct. If you want to use the defined signature SOMETYPE and retain the transparency of the type t, add a constraint to the signature:

    module IntType = (struct type t = int end : SOMETYPE with type t = int)
    
    0 讨论(0)
提交回复
热议问题