Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 3789942
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 19, 20262026-05-19T12:14:13+00:00 2026-05-19T12:14:13+00:00

While browsing the Caml Light library for programming examples, I stumbled across the following

  • 0

While browsing the Caml Light library for programming examples, I stumbled across the following code, taken from the Caml Light queue.ml file:

type 'a queue_cell =
    Nil
  | Cons of 'a * 'a queue_cell ref
;;

type 'a t =
  { 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 entry in the structure, so that appending at the end is possible. This makes perfect sense to me. However, it’s the syntax of how this is done that bugs me.

Consider the following:

  | { tail = Cons(_, ref newtail) as oldtail } ->
      let c = Cons(x, ref Nil) in
        newtail <- c; oldtail <- c

I have a problem with types here. By the type definition, newtail should be of type 'a queue cell, since it’s retrieved using Cons(_, ref newtail) in the pattern matching: if I understand correctly, this would mean that newtail binds the value pointed by the second member of the tail record field (which originally is a reference).

So what does the newtail <- c means? If I try to replace this statement by (fun x -> x <- c) newtail, I get The identifier x is not mutable., whereas the code sounds perfectly similar to the original variant to me.

Would rewriting these few lines to read as follows mean the same?

  | { 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;;

Is it the same to write

{field = Node(n)} -> n := Nil

and

{field = Node(ref n)} -> n <- Nil

?

Even stranger: the following code returns The value identifier a is unbound.

let a = Nil;;
a <- Nil;; (* The value identifier a is unbound. *)

Could someone take the time to clarify the use of <- for me? The various examples here are pretty puzzling to me…
Thanks!

EDIT: This was originally posted to the Caml Mailing list, but I thought the post didn’t make it, so I posted it here. It appears that the posting did work; sorry for that: the link to the mailing list answer (which its original author also posted here), is https://sympa-roc.inria.fr/wws/arc/caml-list/2011-01/msg00190.html.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-19T12:14:14+00:00Added an answer on May 19, 2026 at 12:14 pm

    See my answer on the caml list

    Why ask the same question twice in different places ? This only leads to a duplication of efforts, with knowledgeable people wasting their time to answer you.
    If you want to do that, please at least post cross-references (from your stackoverflow post to the list archive, and vice versa[1]), so that people can check that it hasn’t been answered yet in the other place.

    [1] yes, you can have cyclic cross-references, as the stackoverflow post is mutable!

    The semantics of mutable fields and references has changed a lot (for good)
    between Caml Light and Objective Caml. Beware that this code is Caml Light
    specific — and if you want to learn Caml, you should rather be using
    Objective Caml, which is the implementation that is still maintained.
    In Objective Caml, only records fields are mutable. References are a derived
    concept, the type ‘a ref is defined as :

    type 'a ref = { mutable contents : 'a } 
    

    You change a mutable field with the syntax foo.bar <- baz (where “bar” is
    a record field, and foo and baz are any expression, foo being of a record
    type)

    In Caml Light, record fields are mutable, but sum type fields (variants) are
    mutable as well; mutable variant fields are however not used here. See
    http://caml.inria.fr/pub/docs/manual-caml-light/node4.6.html for
    documentation.

    In Caml Light, a record may return a mutable location, akin to a lvalue in
    C-like languages. For example, with the mutable variant

    type foo = Foo of mutable int 
    

    you may write:

    let set_foo (f : foo) (n : int) = 
      match f with 
      | Foo loc -> 
         loc <- n 
    

    “foo <- bar” is used here to assign a value “bar” to a lvalue “foo” bound in
    a mutable pattern.
    In your example, two mutable patterns are used :

     | { tail = Cons(_, ref newtail) as oldtail } -> 
    
    • oldtail is a mutable pattern denoting the mutable “tail” field of the
      record
    • (ref newtail) is a specific syntax, a pattern on references. It binds a
      mutable pattern “newtail” corresponding to the location of the reference
      In other words, in Caml Light you can write the “:=” operator as such:

      let prefix := r v =
      match r with
      | ref loc ->
      loc <- v

    Hope that helps.

    .

    Edit:

    About the strange error message: I think that internally, Caml Light maintain a list of “value identifiers” in the scope, which come from pattern matching a mutable field (record or variant). When they see a foo <- bar expression, they look in that environment to find the corresponding location. Such environment is local to the expression, it never escapes. In particular at toplevel it is empty, and the errors tells you that no “value identifier” (mutable pattern) exists in the scope.

    There is another thing: the namespace of value identifiers and usual identifiers are not distinct. When you match a value identifier, Caml Light adds to the scope the value identifier (mutable), but also the corresponding identifier with the matched rvalue. This can be quite confusing as you may mutate the location, but the value won’t change :

    #match ref 1 with (ref x) -> (x <- 2; x);;
    - : int = 1
    
    
    #match ref 1 with (ref x) as a -> (x <- 2; !a);;
    - : int = 2
    

    The (value) identifier will shadow any older identifier (value identifier or not)

    #let x = 1 in let (ref x) = ref 2 in x;;
    - : int = 2
    

    (If you didn’t know, let pattern = e1 in e2 is equivalent to match e1 with pattern -> e2 (except for the type system))

    As the syntaxic classes for identifiers and value identifiers are the same, a non-mutable identifier will also shadow a value identifier, giving birth to a different error:

    #let (ref x) = ref 2 in let x = 1 in x <- 3;;
    Toplevel input:
    >let (ref x) = ref 2 in let x = 1 in x <- 3;;
    >                                    ^^^^^^
    The identifier x is not mutable.
    
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

No related questions found

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.