How to match on constructors of abstract data types in OCAML

1) I have this module type

module type MOD_SIG = sig type t val min val max;;

2) I create two modules based on the signature above

module MOD_UINT8 = struct 
  type t = int32 
  let min = Int32.of_int 0 
  let max = Int32.of_int 255 end;;

module MOD_UINT32 = struct 
  type t = int64 
  let min = Int64.zero 
  let max = Int64.of_int 4294967295 end ;;

3) I created first-class modules of 2

let uint_8 = (module MOD_UINT8:MOD_SIG);; 
let uint_32 = (module MOD_UINT32:MOD_SIG);;

4) I want to write a function that accepts a first-class module as an arg and tries to match whether a particular value in that module was of Int32 or Int64.

such as

let module M=(val m:MOD_SIG) in match M.t with 
  | Int32 -> "Int32" 
  | Int64 -> "Int64"

I learned from @octachron that it is not possible. Though I just wanted to raise this question to understand, if there could be a workaround?

Upvotes: 2

Views: 398

Answers (2)

Sventimir
Sventimir

Reputation: 2056

You can't. The exact reason to pack code into modules and make abstract types is so that external code cannot depend on exact implementations. What you can do is abstract over the implementation-dependent behaviour like this:

module type MOD_SIG = sig
    type t
    val min : t
    val max : t
    val name : string
end

let module M = (val m:MOD_SIG) in
M.name

Upvotes: 1

Lhooq
Lhooq

Reputation: 4441

Well, maybe you could add to your modules a function that tells what their particular value is :

type pv = I8 | I32 | I64

module type MOD_SIG = sig 
  type t
  val min 
  val max
  val which_pv : pv
;;

module MOD_UINT8 = struct 
  type t = int32 
  let min = Int32.of_int 0 
  let max = Int32.of_int 255
  let which_pv = I8
end;;

module MOD_UINT32 = struct 
  type t = int64 
  let min = Int64.zero 
  let max = Int64.of_int 4294967295 
  let which_pv = I64
end;;

Actually, sometimes your function depends on what exactly the type t is and that's where functors appears. Let's say, for example, that you want to implement a module about numbers that can be integers, unsigned integers, floats... In this case, the basic operations depend on the exact type and a functor would be better here :

module type NSig = sig
  type t
  val zero : t 
  val one : t
  val min : t
  val max : t
  val add : t -> t -> t
  val mult : t -> t -> t
end;;

module MNumb (N : NSig) = struct
  type t = N.t
  let min = N.min
  let max = N.max
  let add = N.add
  let mult = N.mult
  let rec pow t n = 
    if n = 0 then N.one
    else if n = 1 then t
    else let tt = pow t (n / 2) in
      if n mod 2 = 0 then tt else mult t tt
end;;

As you can see, to create pow I need to know how 1 is represented and mult too but since pow is not a basic function, I'm creating it in the functor. So you'd just have to give your functor the basics of your type (int8, int32, int64, float, fractions...) and feed it to the functor to create the more advanced functions.

Upvotes: 3

Related Questions