I understand that I can coerce from t to int using :> but can I go the other way around?
Is there a way to use coercion here and avoid using of_int here?
module Id : sig
type t = private int
val intern : string -> t
val get : t -> string option
end = struct
type t = int
let of_int n = n
let id = ref (of_int (-1))
let table = Hashtbl.create 100
let intern s =
id := !id + 1;
Hashtbl.add table !id s;
!id
;;
let get id =
try Some (Hashtbl.find table id) with
| Not_found -> None
;;
end
You defined t as a synonym to int, so inside the module, the two are completely interchangeable and you don’t need of_int. int and t are literally the same type here.
From outside the module, t is private, so you only get a coercion in one direction. this is intentional because your t might have more invariants than a plain int, that a coercion in the other direction could break.
I suspect that @joelreymont is running in the syntactic problem (whose details I never remember after all these years) that sometimes using -1 works and sometimes it doesn’t:
# let x = -1;;
val x : int = -1
# let y = succ -1;;
Error: The value succ has type int -> int
but an expression was expected of type int
# let y = succ ~-1;;
val y : int = 0
Note the same occurs with floats:
# let x = -1.0;;
val x : float = -1.
# let x = sin -1.0;;
Error: The value sin has type float -> float
but an expression was expected of type int
# let x = sin ~-1.0;;
Error: The constant 1.0 has type float but an expression was expected of type
int
# let x = sin ~-.1.0;;
val x : float = -0.841470984807896505
❯ cat /tmp/foo.ml
module Id : sig
type t = private int
val intern : string -> t
val get : t -> string option
val compare : t -> t -> int
end = struct
type t = int
let id = ref ~-1
let table = Hashtbl.create 100
let intern s =
id := !id + 1;
Hashtbl.add table !id s;
!id
;;
let get id =
try Some (Hashtbl.find table id) with
| Not_found -> None
;;
let compare a b = Stdlib.compare a b
end
To understand why that is in OCaml, note that “-” comes with two possible (but related) meanings: first, it connotes application of a binary infix subtraction operator, as in 2 - 1, and secondly it connotes the unary prefix negation operator, as in -1.
In OCaml the ~- operator (for integers) and ~-. operator (for floats) represents the second of those.
So given the application of a function f to an integer argument, the form “f -1” won’t compile as it would be construed as an attempt to subtract an integer from a function. The same applies to “ref -1”. You need the form “f ~-1” or disambiguate with parentheses as in “f (-1)” (and likewise for ref).
Sorry if you already know all this but I wasn’t clear to me that that was the case.
I didn’t know about it until I browsed the issue that @dbuenzli posted. I do appreciate your detailed explanation, though. It will save time for anyone stumbling upon this issue in the future!