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.
next prev parent 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