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.

+3


source to share


1 answer


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

      

+5


source







All Articles