caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: oleg@okmij.org
To: gabriel.scherer@gmail.com
Cc: goswin-v-b@web.de, caml-list@inria.fr
Subject: Re: [Caml-list] Why List.map does not be implemented
Date: Wed,  1 Oct 2014 06:29:43 -0400 (EDT)	[thread overview]
Message-ID: <20141001102943.AA0C0C382A@www1.g3.pair.com> (raw)
In-Reply-To: <CAPFanBFyQApQX7rwkjy1PCyKqyyjuP0YauOJcnw58AFoEiyGZg@mail.gmail.com>


Gabriel Scherer wrote
> My intuition would be that the mutation should not be observable in this
> case, as it is only done on "private" data that the List.map function
> allocate, owns, and which never escapes in its immutable form.

Let me explain, on the example of the simplest Hansei function
        val flip : float -> bool
that flips (a possibly unfair) coin; flip 0.5 flips the fair coin.
A good way to understand the meaning of this function is to take the
frequentist approach. There are two ways the function call (flip 0.5)
can return: it can return with true or with false. There are total two
choices, in one of them the function returns true, in another
false. So, the probability of returning true is 1/2. In general, the
complete distribution -- which is the meaning of the program 
(flip 0.5) -- is as follows

# exact_reify (fun () -> flip 0.5);;
- : bool Ptypes.pV = [(0.5, Ptypes.V true); (0.5, Ptypes.V false)]

which is what Hansei computes. Let's take a more complex example,
closer to the topic: two independent coin flips

# let model () = List.map flip [0.5; 0.5]
val model : unit -> bool list = <fun>

# exact_reify model;;
- : bool list Ptypes.pV =
[(0.25, Ptypes.V [true; true]); (0.25, Ptypes.V [true; false]);
 (0.25, Ptypes.V [false; true]); (0.25, Ptypes.V [false; false])]

The result correctly tells that there are four possible choices.

Let us consider the function map from the Batteries. After desugaring,
it has the following form

type 'a mut_list = {
    hd: 'a;
    mutable tl: 'a list
  }

let map : ('a -> 'b) -> 'a list -> 'b list = fun f -> function
  | [] -> []
  | h :: t ->
      let rec loop dst = function
        | [] -> ()
        | h :: t ->
            let cell = {hd = f h; tl = []} in
            dst.tl <- Obj.magic cell;
            loop cell t
      in
      let r = {hd = f h; tl = []} in
      loop r t;
      Obj.magic r

Using this function, we obtain

# let model1 () = map flip [0.5; 0.5]
val model1 : unit -> bool list = <fun>

# exact_reify model1
- : bool list Ptypes.pV =
[(0.5, Ptypes.V [true; false]); (0.5, Ptypes.V [false; false])]

Something went wrong, didn't it? Where are the other two possible
choices -- with true for the second flip -- for the list of two
independent coin flips?

To understand the problem, let us recall the main principle stated
earlier: ``There are two ways the function call (flip 0.5)
can return: it can return with true or with false.'' That is, the
function call (flip 0.5) returns *twice*. Therefore, the call (f h)
in the let cell statement returns twice. Therefore, the assignment
            dst.tl <- Obj.magic cell;
will be executed twice. And the second execution of that assignment
will be with a different cell, which will override and destroy the
result of the first assignment. That is how the "true" choices became
lost.




  reply	other threads:[~2014-10-01 10:29 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-28 19:31 [Caml-list] Why List.map does not be implemented tail-recursively? Shuai Wang
2014-09-28 19:36 ` Gabriel Scherer
2014-09-28 19:45 ` Anthony Tavener
2014-09-29 12:08   ` Goswin von Brederlow
2014-09-29 14:02     ` Pierre Chambart
2014-09-29 15:44       ` Yaron Minsky
2014-09-29 21:00       ` Gabriel Scherer
2014-09-30  8:46         ` [Caml-list] Why List.map does not be implemented oleg
2014-09-30  9:07           ` Gabriel Scherer
2014-10-01 10:29             ` oleg [this message]
2014-10-01 12:00               ` Gerd Stolpmann
2014-10-29 10:11               ` Gabriel Scherer
2014-10-02 10:09         ` [Caml-list] Why List.map does not be implemented tail-recursively? Stephen Dolan
2015-06-01 12:02           ` Jon Harrop
2015-06-02 12:04             ` Stephen Dolan
2015-06-05 10:21               ` Goswin von Brederlow
2014-09-30  6:29       ` Goswin von Brederlow

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20141001102943.AA0C0C382A@www1.g3.pair.com \
    --to=oleg@okmij.org \
    --cc=caml-list@inria.fr \
    --cc=gabriel.scherer@gmail.com \
    --cc=goswin-v-b@web.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).