Dynamic linking using cell ref
I understand that you cannot do this, but you want to understand why exactly.
module M : sig
type 'a t
val call : 'a t -> 'a option
end = struct
type 'a t
let state : ('a t -> 'a option) ref = ref (fun _ -> None)
let call : ('a t -> 'a option) = fun x -> !state x
end
Results in:
Error: Signature mismatch:
Modules do not match:
sig
type 'a t
val state : ('_a t -> '_a option) ref
val call : '_a t -> '_a option
end
is not included in
sig
type 'a t
val call : 'a t -> 'a option
end
Values do not match:
val call : '_a t -> '_a option
is not included in
val call : 'a t -> 'a option
Why are abstract types incompatible here?
My gut tells me that it has everything to do with early and late binding, but I'm looking for an accurate description of what the type system is doing here.
source to share
One way to look at this is that your field state
cannot have the polymorphic value that you assign to it, because mutable values โโcannot be polymorphic. References are most monomorphic (as indicated in the '_a
type variable notation ).
If you just try to declare a similar link at the top level, you will see the same effect:
# let lfr: ('a list -> 'a option) ref = ref (fun x -> None);;
val lfr : ('_a list -> '_a option) ref = {contents = <fun>}
The type of a variable '_a
indicates some single type that has not yet been defined.
The reason why links cannot be polymorphic is because it is not valid. If you allow generalized references (polymorphic), it's easy to create programs that go horribly wrong. (In practice, this usually means a crash and kernel dump.)
The issue of validity is discussed at the beginning of this article: Jacques Garrigue, the relaxing cost constraint (which I talk about occasionally when I forget how things work).
Update
I think you want "rank 2 polymorphism". Ie, you want a field whose type is polymorphic. You can actually get this in OCaml as long as you declare the type. The usual way is to use the post type:
# type lfrec = { mutable f: 'a. 'a list -> 'a option };;
type lfrec = { mutable f : 'a. 'a list -> 'a option; }
# let x = { f = fun x -> None };;
val x : lfrec = {f = <fun>}
# x.f ;;
- : 'a list -> 'a option = <fun>
The following code compiles for me using lfrec
instead of link:
module M : sig
type 'a t
val call : 'a t -> 'a option
end = struct
type 'a t
type lfrec = { mutable f: 'a. 'a t -> 'a option }
let state: lfrec = { f = fun _ -> None }
let call : ('a t -> 'a option) = fun x -> state.f x
end
source to share