caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Thomas Fischbacher <Thomas.Fischbacher@Physik.Uni-Muenchen.DE>
To: skaller <skaller@users.sourceforge.net>
Cc: Martin Chabr <martin_chabr@yahoo.de>,
	Pal-Kristian Engstad <pal_engstad@naughtydog.com>,
	caml-list@yquem.inria.fr
Subject: Re: Ant:  Re: Ant:  Re: [Caml-list] Avoiding shared data
Date: Mon, 3 Oct 2005 15:09:55 +0200 (CEST)	[thread overview]
Message-ID: <Pine.LNX.4.61.0510031406320.28375@eiger.cip.physik.uni-muenchen.de> (raw)
In-Reply-To: <1128300118.10449.136.camel@rosella>


On Mon, 3 Oct 2005, skaller wrote:

> > I hope that one day functional language compilers will
> > do that optimization for you - convert a
> > non-tail-recursive code into a tail-recursive one. Do
> > you know of some progress in that direction?
> 
> Isn't that just CPS? 

He presumably wanted to see a different thing, e.g. 
automatically transforming


let rec fac1 x =
  if x = 0
  then 1
  else x*(fac1 (x-1))
;;

into

let fac2 x =
  let rec walk so_far todo =
    if todo = 0
    then so_far
    else walk (todo*so_far) (todo-1)
  in walk 1 x
;;


My impression is that it may indeed be possible to do something like this 
for simple applications, but that the cases that can be covered 
automatically presumably are so limited that an experienced programmer 
will usually want to attack them by going to a higher form of abstraction 
and not waste time on such things anyway.

I think that Olin Shivers indeed does have a valid point in pointing out 
that writing loops in tail-recursive style has major disadvantages. 
However, my impression still is that as soon as someone thinks in terms of 
"I have to write a loop for this", chances are good that he may improve 
his design by going back one step and ask the question "what do I want to 
use that loop for?". In quite many situations, it is possible to express 
one's thoughts more directly via other means, such as Array.map, 
fold_left, etc. 

What I (as a pedestrian) especially do not like about loops is that it is
much easier to make off-by-one errors than with any form of recursion 
which contains a base-case/recursive-case analysis.


Unfortunately, the OCaml native code compiler apparently is not yet smart 
enough to optimize code written in such a higher-order style well enough 
so that it can compete with imperative or tail-recursive code in 
time-critical applications. (Though quite many applications in fact are 
not.) At present, one can expect to lose about a factor of ~3 in
performance.

Example:

===>
let timing_apply f x =
  let t0 = Unix.gettimeofday() in
  let f_x = f x in
  let t1 = Unix.gettimeofday() in
  (f_x,t1-.t0)
;;

let my_array_fold_left f init arr =
  let len = Array.length arr in
  let rec walk so_far pos =
    if pos=len
    then so_far
    else walk (f so_far arr.(pos)) (1+pos)
  in walk init 0
;;


let test m n =
  let arr =
    Array.init m
      (fun j -> Array.init n (fun k -> j*k+k))
  in
  let scratchpad = ref 0 in
  (* -- *)
  let rec frobenius1 mx =
    Array.fold_left
      (fun so_far row ->
	Array.fold_left
	  (fun so_far entry ->
	    so_far+entry*entry)
	  so_far row)
      0 mx
  in
  let frobenius2 mx =
    my_array_fold_left
      (fun so_far row ->
	my_array_fold_left
	  (fun so_far entry ->
	    so_far+entry*entry)
	  so_far row)
      0 mx
  in
  let frobenius3 mx =
    begin
      scratchpad := 0;
      for i=0 to (Array.length mx)-1 do
	let row = mx.(i) in
	for j=0 to (Array.length row)-1 do
	  scratchpad:= !scratchpad + row.(j)*row.(j);
	done;
      done;
      !scratchpad
    end
  in
  let frobenius4 mx =
    let nr_rows = Array.length mx in
    let rec walk_rows so_far nr_row =
      if nr_row = nr_rows
      then so_far
      else
	let row = mx.(nr_row) in
	let len_row = Array.length row in
	let rec walk_cols so_far nr_col =
	  if nr_col = len_row
	  then so_far
	  else walk_cols (so_far+row.(nr_col)*row.(nr_col)) (1+nr_col)
	in 
	walk_rows (walk_cols so_far 0) (1+nr_row)
    in
    walk_rows 0 0
  in
  let frobenius5 mx =
    let nr_rows = Array.length mx in
    let rec walk_rows so_far nr_row =
      if nr_row = nr_rows
      then so_far
      else
	let row = mx.(nr_row) in
	let len_row = Array.length row in
	let rec walk_cols row so_far nr_col =
	  if nr_col = len_row
	  then so_far
	  else walk_cols row (so_far+row.(nr_col)*row.(nr_col)) (1+nr_col)
	in 
	walk_rows (walk_cols row so_far 0) (1+nr_row)
    in
    walk_rows 0 0
  in
  let compute_n_times n f x =
    let rec walk k =
      if k = n then f x
      else
	let () = ignore(f x) in
	walk (k+1)
    in walk 1
  in
  Array.map
    (fun f -> timing_apply (compute_n_times 1000 f) arr)
    [|frobenius1;frobenius2;frobenius3;frobenius4;frobenius5|]
;;

let result = test 1000 3 in
Array.iteri (fun nr (_,t) -> Printf.printf "%d: %f\n" (1+nr) t) result
;;
<===

ocamlc:

1: 0.987257
2: 1.196910
3: 0.709074
4: 0.858948
5: 0.984935

ocamlopt:

1: 0.066404
2: 0.075691
3: 0.025450
4: 0.025756
5: 0.023472

-- 
regards,               tf@cip.physik.uni-muenchen.de              (o_
 Thomas Fischbacher -  http://www.cip.physik.uni-muenchen.de/~tf  //\
(lambda (n) ((lambda (p q r) (p p q r)) (lambda (g x y)           V_/_
(if (= x 0) y (g g (- x 1) (* x y)))) n 1))                  (Debian GNU)


  parent reply	other threads:[~2005-10-03 13:09 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-09-25 21:32 Martin Chabr
2005-09-26  0:23 ` [Caml-list] " Bill Wood
2005-09-26  7:57 ` Claudio Sacerdoti Coen
2005-09-26  8:17 ` William Lovas
2005-09-26 21:07   ` Ant: " Martin Chabr
2005-09-26 22:08     ` Jon Harrop
2005-09-30 22:57     ` Oliver Bandel
2005-10-01  0:07       ` Pal-Kristian Engstad
2005-10-01  5:46         ` Bill Wood
2005-10-01  8:27         ` Wolfgang Lux
2005-10-01 18:02           ` Wolfgang Lux
2005-10-01 21:50           ` Ant: " Martin Chabr
2005-10-01 12:34         ` Oliver Bandel
2005-10-01 13:58           ` Bill Wood
2005-10-01 21:05         ` Ant: " Martin Chabr
2005-10-03  0:41           ` skaller
2005-10-03  1:13             ` Seth J. Fogarty
2005-10-03 13:09             ` Thomas Fischbacher [this message]
2005-10-03 14:57               ` skaller
2005-10-03 20:03               ` Ant: " Martin Chabr
2005-10-03 20:25                 ` Thomas Fischbacher
2005-10-03 21:08                 ` Jon Harrop
2005-10-04 18:06                   ` Ant: " Martin Chabr
2005-10-04 18:32                     ` Jon Harrop
2005-10-04  2:53                 ` skaller
2005-10-04 16:15                   ` Brian Hurt
2005-10-04 16:47                     ` FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data) Oliver Bandel
2005-10-04 22:38                       ` Michael Wohlwend
2005-10-05  0:31                         ` Jon Harrop
2005-10-04 22:39                       ` Christopher A. Watford
2005-10-04 23:14                         ` Jon Harrop
2005-10-05 12:10                         ` Oliver Bandel
2005-10-05 13:08                           ` Jon Harrop
2005-10-05 15:28                           ` skaller
2005-10-05 20:52                           ` Ant: " Martin Chabr
2005-10-05 23:21                             ` Markus Mottl
2005-10-06 16:54                               ` brogoff
2005-10-05  0:45                       ` Brian Hurt
2005-10-04 18:09                   ` Ant: Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data Martin Chabr
2005-10-05  8:42                     ` skaller
2005-10-05 11:14               ` Andrej Bauer
2005-10-01 21:36       ` Ant: Re: Ant: " Martin Chabr
2005-10-03 11:51         ` getting used to FP-programming (Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data) Oliver Bandel

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=Pine.LNX.4.61.0510031406320.28375@eiger.cip.physik.uni-muenchen.de \
    --to=thomas.fischbacher@physik.uni-muenchen.de \
    --cc=caml-list@yquem.inria.fr \
    --cc=martin_chabr@yahoo.de \
    --cc=pal_engstad@naughtydog.com \
    --cc=skaller@users.sourceforge.net \
    /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).