While viewing the Caml Light library for programming examples, I came across the following code taken from the Caml Light queue.ml :
type 'a queue_cell = Nil | Cons of 'a * 'a queue_cell ref ;; type 'at = { mutable head: 'a queue_cell; mutable tail: 'a queue_cell } ;; let add x = function { head = h; tail = Nil as t } -> (* if tail = Nil then head = Nil *) let c = Cons(x, ref Nil) in h <- c; t <- c | { tail = Cons(_, ref newtail) as oldtail } -> let c = Cons(x, ref Nil) in newtail <- c; oldtail <- c ;;
This implementation of FIFO data structures puzzles me. I get the general idea to keep a pointer to the last record in the structure, so adding at the end is possible. That makes sense to me. However, this is the syntax of how this is done, which scares me.
Consider the following:
| { tail = Cons(_, ref newtail) as oldtail } -> let c = Cons(x, ref Nil) in newtail <- c; oldtail <- c
I have a type problem here. By definition, type newtail should be of type 'a queue cell , since it is extracted using Cons(_, ref newtail) in comparison with the pattern: if I understand correctly, this means that newtail binds the value pointed by the second member of the tail entry field (which is originally a link).
So what does newtail <- c mean? If I try to replace this operator with (fun x -> x <- c) newtail , I get The identifier x is not mutable. , while the code seems to me completely similar to the original version.
Rewriting these few lines to read as follows means the same thing?
| { tail = Cons(_, newtail) as oldtail } -> let c = Cons(x, ref Nil) in newtail := c; oldtail <- c
Taking the question one step further, what does the following code actually do?
type t = Nil | Node of (t ref);; type box = {mutable field: t};; let poke = function | {field = Node(ref n)} -> n <- Nil | {field = Nil} -> () ;; let test = {field = Node(ref (Node(ref Nil)))};; poke test;; test;;
Write the same way
{field = Node(n)} -> n := Nil
and
{field = Node(ref n)} -> n <- Nil
?
Even a stranger: the following code returns The value identifier a is unbound.
let a = Nil;; a <- Nil;; (* The value identifier a is unbound. *)
Can someone spend time clarifying the use of <- for me? The various examples here are quite perplexing to me ...
Thank you
EDIT: This was originally sent to the Caml mailing list, but I thought the message didn't work out, so I posted it here. It seems that the wiring really worked; sorry for this: link to the mailing list response (which was also published by its author) https://sympa-roc.inria.fr/wws/arc/caml-list/2011-01/msg00190.html .