Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract types in modules in OCaml

I have very simple signature and module in OCaml:

module type S = sig
  type t 
  val y : t
end;;

and

module M2 : S = struct
  type t = int
  let x = 1
  let y = x+2
end;;

I cannot use construction like

M2.y

to get 3 unless i specify the module as

module M2 : S with type t = int = struct ...

Why is it so? There already is statement, that type t = int

like image 573
filiard Avatar asked Oct 30 '25 05:10

filiard


1 Answers

The concrete, int value for M2.y is indeed not available because the following two conditions are met:

  1. the type of y is abstract in the signature S
    (there is no type t = ... there)

  2. the module M2 is made opaque with respect to the signature S
    (in other words, it is restricted to the signature S via the notation : S)

As a result, you indeed obtain:

let test = M2.y ;;
(* val test : M2.t = <abstr> *)

As suggested by the keyword <abstr>, this is related to the notion of abstract type. This notion is a very strong feature enforced by OCaml's typing rules, which prevents any user of a module having signature S to inspect the concrete content of one such abstract type. As a result, this property is very useful to implement so-called abstract data types (ADT) in OCaml, by carefully separating the implementation and the signature of the ADT.

If any of the two conditions above is missing, the type won't be abstract anymore and the concrete value of y will show up.

More precisely:

  1. If the type t is made concrete, you obtain:

     module type S = sig
       type t = int
       val y : t
     end
    
     module M2 : S = struct
       type t = int
       let x = 1
       let y = x+2
     end
    
     let test = M2.y ;;
     (* val test : M2.t = 3 *)
    

    But in practice this is not very interesting because you lose generality. However, a somewhat more interesting approach consists in adding an "evaluator" or a "pretty-printer" function to the signature, such as the value int_of_t below:

     module type S = sig
       type t
       val y : t
       val int_of_t : t -> int
     end
    
     module M2 : S = struct
       type t = int
       let x = 1
       let y = x+2
       let int_of_t x = x
     end
    
     let test = M2.(int_of_t y) ;;
     (* val test : int = 3 *)
    
  2. Otherwise, if the module M2 is made transparent, you obtain:

     module type S = sig
       type t
       val y : t
     end
    
     module M2 (* :S *) = struct
       type t = int
       let x = 1
       let y = x+2
     end
    
     let test = M2.y ;;
     (* val test : int = 3 *)
    

Finally, it may be helpful to note that beyond that feature of abstract types, OCaml also provides a feature of private types that can be viewed as a trade-off between concrete and abstract types used in a modular development. For more details on this notion, see for example Chap. 8 of Caml ref man.

like image 130
ErikMD Avatar answered Nov 01 '25 14:11

ErikMD



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!