Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constraining a polymorphic type

Tags:

I've got a range type defined as:

type 'a range = Full | Range of ('a * 'a)

However, I'd like to constrain 'a to be integer or float or char, with no other valid types for 'a.

Range(0,10) (* valid *)
Range(0.0, 10.0) (* valid *)
Range('a', 'z') (* valid *)
Range("string1", "string2") (* other types like this shouldn't type check *)

I figured that I could change my type definitions to:

type sequential   = S_int of int | S_float of float | S_char of char ;;
type range = Full | Range of (sequential * sequential);;

However, this would then allow something like:

Range(S_int(0), S_float(10.0));; (* problem: mixes int and float *)

...but I want both components of Range to be the same type.

I suppose that another approach would be to create an int_range type, a float_range type, and a char_range type but I'm wondering if there's another way?

like image 963
aneccodeal Avatar asked Jun 03 '11 04:06

aneccodeal


1 Answers

Another approach is to declare type private and expose functions constructing it only with the types you want, e.g. :

module Z : sig
  type 'a range = private Full | Range of ('a * 'a)
  val int_range : int -> int -> int range
  val float_range : float -> float -> float range
  val string_range : string -> string -> string range
  val full : 'a range
end = struct
  type 'a range = Full | Range of ('a * 'a)
  let create x y = Range (x,y)
  let int_range = create
  let float_range = create
  let string_range = create
  let full = Full
end

# open Z;;
# int_range 2 3;;
- : int Z.range = Range (2, 3)
# Range ('a','c');;
Error: Cannot create values of the private type char Z.range
like image 153
ygrek Avatar answered Oct 12 '22 13:10

ygrek