caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* OCaml troll on Slashdot
@ 2005-03-15  1:29 Karl Zilles
  2005-03-15  8:32 ` [Caml-list] " Oliver Bandel
  2005-03-15  9:25 ` Richard Jones
  0 siblings, 2 replies; 71+ messages in thread
From: Karl Zilles @ 2005-03-15  1:29 UTC (permalink / raw)
  To: Caml Mailing List

http://developers.slashdot.org/article.pl?sid=05/03/14/2258219


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  1:29 OCaml troll on Slashdot Karl Zilles
@ 2005-03-15  8:32 ` Oliver Bandel
  2005-03-15  8:45   ` Michael Vanier
  2005-03-15 20:06   ` Yoann Padioleau
  2005-03-15  9:25 ` Richard Jones
  1 sibling, 2 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-15  8:32 UTC (permalink / raw)
  To: caml-list

On Mon, Mar 14, 2005 at 05:29:42PM -0800, Karl Zilles wrote:
> http://developers.slashdot.org/article.pl?sid=05/03/14/2258219
[...]


Well, I used the code that is provided there.
And it runs on my computer not 16 minutes...


=====================
(...)
4 by 10
10 empty cells:
XXOX
OXXX
XXXO
XOXX
XXXO
OXXX
XXOX
OXXX
XXXO
XOXX


real    0m10.677s
user    0m9.440s
sys     0m0.040s
=====================
(with ocamlc)

=====================
real    0m7.583s
user    0m6.390s
sys     0m0.020s
 (with ocamlopt)
=====================


So the whole discussion is stiupid...

Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  8:32 ` [Caml-list] " Oliver Bandel
@ 2005-03-15  8:45   ` Michael Vanier
  2005-03-15  8:59     ` Jon Harrop
  2005-03-15 20:06   ` Yoann Padioleau
  1 sibling, 1 reply; 71+ messages in thread
From: Michael Vanier @ 2005-03-15  8:45 UTC (permalink / raw)
  To: oliver; +Cc: caml-list


Maybe he hasn't discovered ocamlopt yet.

Mike

> Date: Tue, 15 Mar 2005 09:32:43 +0100
> From: Oliver Bandel <oliver@first.in-berlin.de>
> 
> On Mon, Mar 14, 2005 at 05:29:42PM -0800, Karl Zilles wrote:
> > http://developers.slashdot.org/article.pl?sid=05/03/14/2258219
> [...]
> 
> 
> Well, I used the code that is provided there.
> And it runs on my computer not 16 minutes...
> 
> 
> =====================
> (...)
> 4 by 10
> 10 empty cells:
> XXOX
> OXXX
> XXXO
> XOXX
> XXXO
> OXXX
> XXOX
> OXXX
> XXXO
> XOXX
> 
> 
> real    0m10.677s
> user    0m9.440s
> sys     0m0.040s
> =====================
> (with ocamlc)
> 
> =====================
> real    0m7.583s
> user    0m6.390s
> sys     0m0.020s
>  (with ocamlopt)
> =====================
> 
> 
> So the whole discussion is stiupid...
> 
> Ciao,
>    Oliver
> 


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  8:45   ` Michael Vanier
@ 2005-03-15  8:59     ` Jon Harrop
  2005-03-15 20:17       ` Yoann Padioleau
  2005-03-31 11:41       ` Paul Argentoff
  0 siblings, 2 replies; 71+ messages in thread
From: Jon Harrop @ 2005-03-15  8:59 UTC (permalink / raw)
  To: caml-list

On Tuesday 15 March 2005 08:45, Michael Vanier wrote:
> Maybe he hasn't discovered ocamlopt yet.

No, the OCaml code (compiled with ocamlopt) is much, much slower than the C++. 
As we all know, this can mean only one thing...

Also, his C++ is actually shorter than the OCaml, and the OCaml defines a lot 
of familiar looking functions (map, length, "prepend" etc.).

I'll take a more detailed look in a minute...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  1:29 OCaml troll on Slashdot Karl Zilles
  2005-03-15  8:32 ` [Caml-list] " Oliver Bandel
@ 2005-03-15  9:25 ` Richard Jones
  2005-03-15 10:08   ` YANG Shouxun
  2005-03-15 10:34   ` padiolea
  1 sibling, 2 replies; 71+ messages in thread
From: Richard Jones @ 2005-03-15  9:25 UTC (permalink / raw)
  Cc: Caml Mailing List

On Mon, Mar 14, 2005 at 05:29:42PM -0800, Karl Zilles wrote:
> http://developers.slashdot.org/article.pl?sid=05/03/14/2258219

The problem was with his stupid implementation of a hash table:

http://developers.slashdot.org/comments.pl?sid=142494&cid=11939530

(That comment is +5 informative)

Rich.

-- 
Richard Jones, CTO Merjis Ltd.
Merjis - web marketing and technology - http://merjis.com
Team Notepad - intranets and extranets for business - http://team-notepad.com


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  9:25 ` Richard Jones
@ 2005-03-15 10:08   ` YANG Shouxun
  2005-03-15 20:02     ` Yoann Padioleau
  2005-03-15 10:34   ` padiolea
  1 sibling, 1 reply; 71+ messages in thread
From: YANG Shouxun @ 2005-03-15 10:08 UTC (permalink / raw)
  To: caml-list

On Tuesday 15 March 2005 17:25, Richard Jones wrote:
> On Mon, Mar 14, 2005 at 05:29:42PM -0800, Karl Zilles wrote:
> > http://developers.slashdot.org/article.pl?sid=05/03/14/2258219
>
> The problem was with his stupid implementation of a hash table:
>
> http://developers.slashdot.org/comments.pl?sid=142494&cid=11939530
>
> (That comment is +5 informative)

No. My experiments show that the OCaml implementation performs far better than 
the C++ implementation when the column and row get larger:

C++ is compiled with -O3, not sure what is the better optimization level, 
while OCaml version (actually I used Sys.argv and references to the two 
parameters) is compiled with ocamlopt

4x4 c++
real    0m0.003s
user    0m0.002s
sys     0m0.002s

4x4 ocaml
real    0m0.177s
user    0m0.137s
sys     0m0.001s

8x8 c++
real    0m8.703s
user    0m7.000s
sys     0m0.018s

8x8 ocaml
real    0m0.747s
user    0m0.485s
sys     0m0.002s

12x12 c++
the process was killed by the OS

12x12 ocaml
real    0m1.210s
user    0m0.886s
sys     0m0.001s


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  9:25 ` Richard Jones
  2005-03-15 10:08   ` YANG Shouxun
@ 2005-03-15 10:34   ` padiolea
  2005-03-15 10:52     ` Diego Olivier Fernandez Pons
  2005-03-15 14:12     ` Eijiro Sumii
  1 sibling, 2 replies; 71+ messages in thread
From: padiolea @ 2005-03-15 10:34 UTC (permalink / raw)
  To: Richard Jones; +Cc: Caml Mailing List

> On Mon, Mar 14, 2005 at 05:29:42PM -0800, Karl Zilles wrote:
>> http://developers.slashdot.org/article.pl?sid=05/03/14/2258219
>
> The problem was with his stupid implementation of a hash table:

Perhaps his program is not good.
But he made a point. His experience say something
and I agree with many stuff he said.

In the ICFP 2000 contest, the mercury team advocated that
their program was very fast and so implicitly claimed
that logic programming was very fast, but if you look at
their code they mostly used a functionnal style,
not a logic style.


I think it is a bad idea to call "troll" someone who is
against ocaml, especially when he says something true.
Perhaps the webpage of ocaml should put a warning
 "ocaml can compete against C, but it is not magical,
  a beginner will certainly make very inefficient program".


PS: I am a big fan of functionnal programming, and I try as much
as possible to make functionnal code, but it is true that sometimes
I have to renounce to this and go back to imperative style because
it would be inefficient.


>
> http://developers.slashdot.org/comments.pl?sid=142494&cid=11939530
>
> (That comment is +5 informative)
>
> Rich.
>
> --
> Richard Jones, CTO Merjis Ltd.
> Merjis - web marketing and technology - http://merjis.com
> Team Notepad - intranets and extranets for business -
> http://team-notepad.com
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>



^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 10:34   ` padiolea
@ 2005-03-15 10:52     ` Diego Olivier Fernandez Pons
  2005-03-15 14:12     ` Eijiro Sumii
  1 sibling, 0 replies; 71+ messages in thread
From: Diego Olivier Fernandez Pons @ 2005-03-15 10:52 UTC (permalink / raw)
  To: caml-list

    Bonjour,

> Perhaps the webpage of ocaml should put a warning
>  "ocaml can compete against C, but it is not magical,
>   a beginner will certainly make very inefficient program".

Well, my Caml code may be inefficent but it has an important advantage
over my C++ code :
- it exists
- it works

Maybe should we also warn beginners that when they will try to port
their caml code in C++ to see how much they are loosing because of
Caml, they will spend a very very bad time.

        Diego Olivier


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 10:34   ` padiolea
  2005-03-15 10:52     ` Diego Olivier Fernandez Pons
@ 2005-03-15 14:12     ` Eijiro Sumii
  2005-03-15 15:25       ` Christophe TROESTLER
  1 sibling, 1 reply; 71+ messages in thread
From: Eijiro Sumii @ 2005-03-15 14:12 UTC (permalink / raw)
  To: caml-list; +Cc: sumii

> Perhaps his program is not good.
> But he made a point. His experience say something
> and I agree with many stuff he said.

I don't think he says _anything_ correct except trivial facts (like
his OCaml program is very slow:-) - but this is because it is written
_extremely_ poorly).

As we can see from the careful wording at caml.inria.fr (both the new
one and the old one), OCaml is *not* defined as a functional language.
In fact, it is good even at imperative/OO programming thanks to
garbage collection, parametric polymorphism, data types, pattern
matching, etc.!

--
Eijiro Sumii (http://www.cis.upenn.edu/~sumii/)
Department of Computer and Information Science, University of Pennsylvania


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 14:12     ` Eijiro Sumii
@ 2005-03-15 15:25       ` Christophe TROESTLER
  2005-03-15 18:05         ` Thomas Fischbacher
  2005-03-15 18:55         ` Christopher A. Watford
  0 siblings, 2 replies; 71+ messages in thread
From: Christophe TROESTLER @ 2005-03-15 15:25 UTC (permalink / raw)
  To: O'Caml Mailing List

On Tue, 15 Mar 2005, Eijiro Sumii <eijiro_sumii@anet.ne.jp> wrote:
> 
> > Perhaps his program is not good.  But he made a point. His
> > experience say something and I agree with many stuff he said.
> 
> I don't think he says _anything_ correct except trivial facts [...]

I agree with that.  The ./ post is a typical
I-don't-know-what-I-am-talking-about-so-I-say-it-loud !  If he made a
point I believe it is that it's easier to hit the "send" key than to
try to be a good programmer...

> As we can see from the careful wording at caml.inria.fr (both the
> new one and the old one), OCaml is *not* defined as a functional
> language.  In fact, it is good even at imperative/OO programming
> thanks to garbage collection, parametric polymorphism, data types,
> pattern matching, etc.!

In that vein, I like Doug Bagley koans.  Here is the one about HOF:

  A disciple who was a recent convert from another sect felt troubled
  by the teachings of his former master, who taught the dogma that
  only referentially transparent languages have Functional Nature. So
  he asks his new master, Pierre Weis: "Does OCaml have Functional
  Nature?", to which wise master replied: "HOF!" On hearing the
  mystical incantation, the new convert was enlightened.

My 2¢,
ChriS


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 15:25       ` Christophe TROESTLER
@ 2005-03-15 18:05         ` Thomas Fischbacher
  2005-03-15 18:26           ` Kip Macy
  2005-03-15 18:55         ` Christopher A. Watford
  1 sibling, 1 reply; 71+ messages in thread
From: Thomas Fischbacher @ 2005-03-15 18:05 UTC (permalink / raw)
  To: Christophe TROESTLER; +Cc: O'Caml Mailing List


On Tue, 15 Mar 2005, Christophe TROESTLER wrote:

> I agree with that.  The ./ post is a typical
> I-don't-know-what-I-am-talking-about-so-I-say-it-loud !  If he made a
> point I believe it is that it's easier to hit the "send" key than to
> try to be a good programmer...

Isn't it sad that those people generate so much more noise than those who 
know how to program and really do cool stuff with ocaml?

-- 
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)


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 18:05         ` Thomas Fischbacher
@ 2005-03-15 18:26           ` Kip Macy
  2005-03-16  0:32             ` Oliver Bandel
  2005-03-16 11:26             ` David Fox
  0 siblings, 2 replies; 71+ messages in thread
From: Kip Macy @ 2005-03-15 18:26 UTC (permalink / raw)
  To: Thomas Fischbacher; +Cc: Christophe TROESTLER, O'Caml Mailing List

Most people who do things well are too busy doing them to have time to
talk about them.

     -Kip


On Tue, 15 Mar 2005 19:05:10 +0100 (CET), Thomas Fischbacher
<Thomas.Fischbacher@physik.uni-muenchen.de> wrote:
> 
> On Tue, 15 Mar 2005, Christophe TROESTLER wrote:
> 
> > I agree with that.  The ./ post is a typical
> > I-don't-know-what-I-am-talking-about-so-I-say-it-loud !  If he made a
> > point I believe it is that it's easier to hit the "send" key than to
> > try to be a good programmer...
> 
> Isn't it sad that those people generate so much more noise than those who
> know how to program and really do cool stuff with ocaml?
> 
> --
> 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)
> 
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 15:25       ` Christophe TROESTLER
  2005-03-15 18:05         ` Thomas Fischbacher
@ 2005-03-15 18:55         ` Christopher A. Watford
  2005-03-15 19:56           ` Jon Harrop
  2005-03-16  0:34           ` Oliver Bandel
  1 sibling, 2 replies; 71+ messages in thread
From: Christopher A. Watford @ 2005-03-15 18:55 UTC (permalink / raw)
  To: Christophe TROESTLER; +Cc: O'Caml Mailing List

On Tue, 15 Mar 2005 16:25:01 +0100 (CET), Christophe TROESTLER
<debian00@tiscali.be> wrote:
> I agree with that.  The ./ post is a typical
> I-don't-know-what-I-am-talking-about-so-I-say-it-loud !  If he made a
> point I believe it is that it's easier to hit the "send" key than to
> try to be a good programmer...
>
><SNIP>
>
> My 2¢,
> ChriS

You're right, it looked something like this to me:

Hi! I'm new to OCaml, and my first attempt and making something like I
would in C++ failed miserably. I didn't used standard library
functions, because I didn't know they existed. I also went ahead and
compiled things in a rediculously unoptimized fashion. Finally, I
didn't bother comparing how my noobie code scaled against the C++.
LIKE OMG OCAML SUX0R!

People post similar things for C#, PHP, any language really. Besides,
it is VERY VERY simple to troll slashdot.

-- 
Christopher A. Watford
christopher.watford@gmail.com
http://dorm.tunkeymicket.com


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 18:55         ` Christopher A. Watford
@ 2005-03-15 19:56           ` Jon Harrop
  2005-03-16  0:35             ` Oliver Bandel
  2005-03-16  0:34           ` Oliver Bandel
  1 sibling, 1 reply; 71+ messages in thread
From: Jon Harrop @ 2005-03-15 19:56 UTC (permalink / raw)
  To: caml-list

On Tuesday 15 March 2005 18:55, Christopher A. Watford wrote:
> On Tue, 15 Mar 2005 16:25:01 +0100 (CET), Christophe TROESTLER
> You're right, it looked something like this to me:
>
> Hi! I'm new to OCaml, and my first attempt and making something like I
> would in C++ failed miserably.

Perhaps this isn't the best forum to be saying this, but that guy's C++ code 
sucked as well. It could have been a lot more concise and efficient if he'd 
actually used C++...

Maybe the task will get on the shootout and we can do it properly in OCaml.

On Tuesday 15 March 2005 18:26, Kip Macy wrote:
> Most people who do things well are too busy doing them to have time to
> talk about them.

Yes, I have to resort to putting it in my sig. ;-)

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 10:08   ` YANG Shouxun
@ 2005-03-15 20:02     ` Yoann Padioleau
  2005-03-15 22:33       ` Richard Jones
  2005-03-16  1:33       ` YANG Shouxun
  0 siblings, 2 replies; 71+ messages in thread
From: Yoann Padioleau @ 2005-03-15 20:02 UTC (permalink / raw)
  To: YANG Shouxun; +Cc: caml-list

YANG Shouxun <yang.shx@fltrp.com> writes:

> No. My experiments show that the OCaml implementation performs far better than 
> the C++ implementation when the column and row get larger:

Perhaps because you are a liar.

> 
> C++ is compiled with -O3, not sure what is the better optimization level, 
> while OCaml version (actually I used Sys.argv and references to the two 
> parameters) is compiled with ocamlopt
> 
> 4x4 c++
> real    0m0.003s
> user    0m0.002s
> sys     0m0.002s
> 
> 4x4 ocaml
> real    0m0.177s
> user    0m0.137s
> sys     0m0.001s
> 
> 8x8 c++
> real    0m8.703s
> user    0m7.000s
> sys     0m0.018s
> 
> 8x8 ocaml
> real    0m0.747s
> user    0m0.485s
> sys     0m0.002s

I dont know where you get those numbers ? 
I tried the code of the "troll" and the ocaml version performs far _worse_ than
the c++ implementation when the column and row get larger.


> 
> 12x12 c++
> the process was killed by the OS
> 
> 12x12 ocaml
> real    0m1.210s
> user    0m0.886s
> sys     0m0.001s
> 
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
> 

-- 
Yoann  Padioleau,  INSA de Rennes, France   www.irisa.fr/prive/padiolea/
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**____   Get Free. Be Smart.  Simply use Linux and Free Software.   ____**


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  8:32 ` [Caml-list] " Oliver Bandel
  2005-03-15  8:45   ` Michael Vanier
@ 2005-03-15 20:06   ` Yoann Padioleau
  1 sibling, 0 replies; 71+ messages in thread
From: Yoann Padioleau @ 2005-03-15 20:06 UTC (permalink / raw)
  To: Oliver Bandel; +Cc: caml-list

Oliver Bandel <oliver@first.in-berlin.de> writes:

> On Mon, Mar 14, 2005 at 05:29:42PM -0800, Karl Zilles wrote:
> > http://developers.slashdot.org/article.pl?sid=05/03/14/2258219
> [...]
> 
> 
> Well, I used the code that is provided there.
> And it runs on my computer not 16 minutes...

try 7 by 7 and you will see that it effectively more than 16 minutes.

> 
> 
> =====================
> (...)
> 4 by 10
> 10 empty cells:
> XXOX
> OXXX
> XXXO
> XOXX
> XXXO
> OXXX
> XXOX
> OXXX
> XXXO
> XOXX
> 
> 
> real    0m10.677s
> user    0m9.440s
> sys     0m0.040s
> =====================
> (with ocamlc)
> 
> =====================
> real    0m7.583s
> user    0m6.390s
> sys     0m0.020s
>  (with ocamlopt)
> =====================
> 
> 
> So the whole discussion is stiupid...
> 
> Ciao,
>    Oliver
> 
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
> 

-- 
Yoann  Padioleau,  INSA de Rennes, France   www.irisa.fr/prive/padiolea/
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**____   Get Free. Be Smart.  Simply use Linux and Free Software.   ____**


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  8:59     ` Jon Harrop
@ 2005-03-15 20:17       ` Yoann Padioleau
  2005-03-15 20:36         ` Jon Harrop
  2005-03-31 11:42         ` Paul Argentoff
  2005-03-31 11:41       ` Paul Argentoff
  1 sibling, 2 replies; 71+ messages in thread
From: Yoann Padioleau @ 2005-03-15 20:17 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

Jon Harrop <jon@ffconsultancy.com> writes:

> On Tuesday 15 March 2005 08:45, Michael Vanier wrote:
> > Maybe he hasn't discovered ocamlopt yet.
> 
> No, the OCaml code (compiled with ocamlopt) is much, much slower than the C++. 
> As we all know, this can mean only one thing...
> 
> Also, his C++ is actually shorter than the OCaml, and the OCaml defines a lot 
> of familiar looking functions (map, length, "prepend" etc.).
> 
> I'll take a more detailed look in a minute...

I have made the obvious optimization which is to replace the assoc list by 
a Map (just changing 4 lines in the "troll" code),
the ocaml version is then far far faster.

But computing 7 by 7 with c++ take 1.5 sec and with 
ocaml 50.0 sec (but it is better than "more than 16 minutes").




-- 
Yoann  Padioleau,  INSA de Rennes, France   www.irisa.fr/prive/padiolea/
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**____   Get Free. Be Smart.  Simply use Linux and Free Software.   ____**


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 20:17       ` Yoann Padioleau
@ 2005-03-15 20:36         ` Jon Harrop
  2005-03-15 21:03           ` padiolea
  2005-03-31 11:42         ` Paul Argentoff
  1 sibling, 1 reply; 71+ messages in thread
From: Jon Harrop @ 2005-03-15 20:36 UTC (permalink / raw)
  To: caml-list

On Tuesday 15 March 2005 20:17, Yoann Padioleau wrote:
> I have made the obvious optimization which is to replace the assoc list by
> a Map (just changing 4 lines in the "troll" code),
> the ocaml version is then far far faster.
>
> But computing 7 by 7 with c++ take 1.5 sec and with
> ocaml 50.0 sec (but it is better than "more than 16 minutes").

I spent a little time on it but some Anonymous Coward has already done a much 
better job and posted the resulting code on Jacques Garrigue's website. ;-)

I also posted the resulting timings on slashdot. IIRC, OCaml was less than 
half as much code and ran in 1.66 times the time (if you unroll the most time 
consuming function a little). That's pretty much what I'd expect given that 
the problem is too simple and array-based to take much advantage of OCaml and 
functional programming.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 20:36         ` Jon Harrop
@ 2005-03-15 21:03           ` padiolea
  2005-03-15 21:40             ` William D.Neumann
  2005-03-16  1:38             ` Jacques Garrigue
  0 siblings, 2 replies; 71+ messages in thread
From: padiolea @ 2005-03-15 21:03 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

> On Tuesday 15 March 2005 20:17, Yoann Padioleau wrote:
>> I have made the obvious optimization which is to replace the assoc list
>> by
>> a Map (just changing 4 lines in the "troll" code),
>> the ocaml version is then far far faster.
>>
>> But computing 7 by 7 with c++ take 1.5 sec and with
>> ocaml 50.0 sec (but it is better than "more than 16 minutes").
>
> I spent a little time on it but some Anonymous Coward has already done a
> much
> better job and posted the resulting code on Jacques Garrigue's website.
> ;-)

where ?

>
> I also posted the resulting timings on slashdot. IIRC, OCaml was less than
> half as much code and ran in 1.66 times the time (if you unroll the most
> time
> consuming function a little). That's pretty much what I'd expect given
> that
> the problem is too simple and array-based to take much advantage of OCaml
> and
> functional programming.

Yes but this ocaml code use array ?
In that case it supports what the "troll" said, that is
the resulting code is no more "functionnal".
I agree with eijro sumii that ocaml is not just about functionnal
programming but in the mind of many people advocating ocaml is advocating
functionnal programming.

I think the way to answer to those trolls is to teach them the way
to do, in that case to use Map instead of associative list, and
not to be pretentious and to tell that he is just a newbie.
He is not a newbie, this garden optimization problem is not that simple.

Perhaps the python/perl/ruby community are successful because they
answer to those "trolls" who often then become the first
advocater of the langage who in turn answer to other "trolls" which
make the community bigger and bigger.

I am an egoist so I dont really care that this guy use ocaml,
but the more people use ocaml, the more I will have a chance to
get a job where I am paid to code in caml :)


>
> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.
> Objective CAML for Scientists
> http://www.ffconsultancy.com/products/ocaml_for_scientists
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>





^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 21:03           ` padiolea
@ 2005-03-15 21:40             ` William D.Neumann
  2005-03-15 22:12               ` Yoann Padioleau
  2005-03-16  1:38             ` Jacques Garrigue
  1 sibling, 1 reply; 71+ messages in thread
From: William D.Neumann @ 2005-03-15 21:40 UTC (permalink / raw)
  To: padiolea; +Cc: Jon Harrop, caml-list

On Mar 15, 2005, at 2:03 PM, padiolea@irisa.fr wrote:

> where ?

http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/garden2.ml

> Yes but this ocaml code use array ?

Lists and arrays.  Each where it's appropriate.

> In that case it supports what the "troll" said, that is
> the resulting code is no more "functionnal".

To which, I'd assume the majority response would be, "So?"  And to 
which I might add Benjamin Pierce's comment, "Most arguments about 
'What is the essence of...?' do more to reveal the prejudices of the 
participants than to uncover any objective truth about the topic of 
discussion.  Attempts to define the term 'object-oriented' are no 
exception."  Sure, he wrote it in regards to object oriented 
programming, but it fits functional programming very well (a 
polymorphic comment, indeed).

>  He is not a newbie, this garden optimization problem is not that 
> simple.

Well, a five minute glance at the code seems to indicate a very shallow 
understanding of OCaml.  He might be a wizard in other aspects of 
programming/CS, but dollars to donuts he's very much an OCaml newbie.

> Perhaps the python/perl/ruby community are successful because they
> answer to those "trolls" who often then become the first
> advocater of the langage who in turn answer to other "trolls" which
> make the community bigger and bigger.

I dunno.  A couple of days ago there was a /. story about the new 
Randal Schwartz book, and at least one person was complaining about the 
perl newsgroups/mailing lists being full of unfriendly, unhelpful folk.

William D. Neumann

"You've got Rita Marlowe in the palm of your hand."
"Palm of my hand?  You haven't seen Rita Marlowe..."

		-- Will Success Spoil Rock Hunter?


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 21:40             ` William D.Neumann
@ 2005-03-15 22:12               ` Yoann Padioleau
  2005-03-15 23:07                 ` William D.Neumann
  0 siblings, 1 reply; 71+ messages in thread
From: Yoann Padioleau @ 2005-03-15 22:12 UTC (permalink / raw)
  To: William D.Neumann; +Cc: padiolea, Jon Harrop, caml-list

"William D.Neumann" <wneumann@cs.unm.edu> writes:

> On Mar 15, 2005, at 2:03 PM, padiolea@irisa.fr wrote:
> 
> > where ?
> 
> http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/garden2.ml
> 
> > Yes but this ocaml code use array ?
> 
> Lists and arrays.  Each where it's appropriate.

I agree.

> 
> > In that case it supports what the "troll" said, that is
> > the resulting code is no more "functionnal".
> 
> To which, I'd assume the majority response would be, "So?"  

So some of his arguments are right. You make object "So?" but 
we could continue a long moment that way.

> And to
> which I might add Benjamin Pierce's comment, "Most arguments about
> 'What is the essence of...?' do more to reveal the prejudices of the
> participants than to uncover any objective truth about the topic of
> discussion.  Attempts to define the term 'object-oriented' are no
> exception."  Sure, he wrote it in regards to object oriented
> programming, but it fits functional programming very well 

Well not trying to define stuff is better ? 

> (a  polymorphic comment, indeed).

:)

> 
> >  He is not a newbie, this garden optimization problem is not that
> > simple.
> 
> Well, a five minute glance at the code seems to indicate a very
> shallow understanding of OCaml.  He might be a wizard in other aspects
> of programming/CS, but dollars to donuts 

"dollars to donuts" ? 
I am an american newbie so I have no idea of what it means :)

> he's very much an OCaml newbie.

He is far better than most of my students.
It all depends on what you call a newbie.
We are all the newbie of someone else (except perhaps xavier leroy, eijiro sumii and company).

> 
> > Perhaps the python/perl/ruby community are successful because they
> > answer to those "trolls" who often then become the first
> > advocater of the langage who in turn answer to other "trolls" which
> > make the community bigger and bigger.
> 
> I dunno.  A couple of days ago there was a /. story about the new
> Randal Schwartz book, and at least one person was complaining about
> the perl newsgroups/mailing lists being full of unfriendly, unhelpful
> folk.

yes but there is also full of friendly helpful folks.

> 
> William D. Neumann
> 
> "You've got Rita Marlowe in the palm of your hand."
> "Palm of my hand?  You haven't seen Rita Marlowe..."
> 
> 		-- Will Success Spoil Rock Hunter?
> 
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
> 

-- 
Yoann  Padioleau,  INSA de Rennes, France   www.irisa.fr/prive/padiolea/
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**____   Get Free. Be Smart.  Simply use Linux and Free Software.   ____**


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 20:02     ` Yoann Padioleau
@ 2005-03-15 22:33       ` Richard Jones
  2005-03-16  1:33       ` YANG Shouxun
  1 sibling, 0 replies; 71+ messages in thread
From: Richard Jones @ 2005-03-15 22:33 UTC (permalink / raw)
  To: caml-list

Keep it civilised please people :-)

Rich.

-- 
Richard Jones, CTO Merjis Ltd.
Merjis - web marketing and technology - http://merjis.com
Team Notepad - intranets and extranets for business - http://team-notepad.com


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 22:12               ` Yoann Padioleau
@ 2005-03-15 23:07                 ` William D.Neumann
  2005-03-15 23:39                   ` Jon Harrop
                                     ` (2 more replies)
  0 siblings, 3 replies; 71+ messages in thread
From: William D.Neumann @ 2005-03-15 23:07 UTC (permalink / raw)
  To: Yoann Padioleau; +Cc: caml-list

On Mar 15, 2005, at 3:12 PM, Yoann Padioleau wrote:

>> To which, I'd assume the majority response would be, "So?"
>
> So some of his arguments are right. You make object "So?" but
> we could continue a long moment that way.

Perhaps, perhaps not.  His point seems to be that programming in a 
"functional style"[1] is inherently slower than an imperative style 
because a list or a map have different performance characteristics than 
do arrays.  To which the only response is along the lines of "True.  
They are different data structures, and they behave differently -- 
sometimes worse, sometimes better."  But the point is that needlessly 
restricting yourself to such a style seems like such an odd thing to do 
that I have a hard time caring about the truth of the assertion.  The 
truth of a statement is orthogonal to its silliness.

> Well not trying to define stuff is better ?

That's not really the intent of the quote (or at least I don't think it 
is).  I read it as saying that those who insist that e.g. "functional 
programming" *cannot* include the notion of mutable data structures, or 
that it *cannot* be OO if it doesn't offer encapsulation or classes, 
aren't really bringing anything useful to the table.  You can argue 
'till you're blue in the face whether or not mutable arrays or strings 
have any place in a "functional" language, but when you're done, have 
you really accomplished anything?

> "dollars to donuts" ?
> I am an american newbie so I have no idea of what it means :)

Sorry.  It's shorthand for "I'll wager my X dollars against your X 
donuts that I am correct," and is a way of expressing confidence in 
your position.  It used to mean a lot more when you could get a dozen 
donuts for a dollar...

[1] Where functional style is restricted to, among other things, no 
mutable data structures.

William D. Neumann

"You've got Rita Marlowe in the palm of your hand."
"Palm of my hand?  You haven't seen Rita Marlowe..."

		-- Will Success Spoil Rock Hunter?


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 23:07                 ` William D.Neumann
@ 2005-03-15 23:39                   ` Jon Harrop
  2005-03-15 23:54                     ` Thomas Fischbacher
  2005-03-16  0:03                   ` Christopher Dutchyn
  2005-03-16  0:18                   ` Oliver Bandel
  2 siblings, 1 reply; 71+ messages in thread
From: Jon Harrop @ 2005-03-15 23:39 UTC (permalink / raw)
  To: caml-list

On Tuesday 15 March 2005 23:07, William D.Neumann wrote:
> His point seems to be that programming in a
> "functional style"[1] is inherently slower than an imperative style
> because a list or a map have different performance characteristics than
> do arrays.

True, but don't forget that using arrays does not imply imperative programming 
in general. For example, I partook in a thread on c.l.functional recently, 
comparing the performance of the sieve of Erasthenes (I know, a 
microbenchmark) in different languages. With a purely functional 
implementation of arrays, the Haskell implementation beat C++ (with 
vector<bool>) and was even competing with OCaml for a short while!

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 23:39                   ` Jon Harrop
@ 2005-03-15 23:54                     ` Thomas Fischbacher
  0 siblings, 0 replies; 71+ messages in thread
From: Thomas Fischbacher @ 2005-03-15 23:54 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list


On Tue, 15 Mar 2005, Jon Harrop wrote:

> With a purely functional implementation of arrays,

Rather, with a purely functional implementation of the description of 
array operations.


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 23:07                 ` William D.Neumann
  2005-03-15 23:39                   ` Jon Harrop
@ 2005-03-16  0:03                   ` Christopher Dutchyn
  2005-03-16  0:18                   ` Oliver Bandel
  2 siblings, 0 replies; 71+ messages in thread
From: Christopher Dutchyn @ 2005-03-16  0:03 UTC (permalink / raw)
  To: William D.Neumann; +Cc: Yoann Padioleau, caml-list


On Tue, 15 Mar 2005, William D.Neumann wrote:

> His point seems to be that programming in a "functional style"[1] is 
> inherently slower than an imperative style because a list or a map have 
> different performance characteristics than do arrays.

Nick Pippinger gave the first crisp result comparing performance of 
functional and imperative languages in "Pure vs Impure Lisp" [POPL 1996]. 
Researchers like Oege de Moor are working on characterizing more of these 
differences.

--
Christopher Dutchyn
UBC Computer Science



^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 23:07                 ` William D.Neumann
  2005-03-15 23:39                   ` Jon Harrop
  2005-03-16  0:03                   ` Christopher Dutchyn
@ 2005-03-16  0:18                   ` Oliver Bandel
  2005-03-16  1:05                     ` Yoann Padioleau
  2005-03-16  3:01                     ` Jon Harrop
  2 siblings, 2 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-16  0:18 UTC (permalink / raw)
  To: caml-list

On Tue, Mar 15, 2005 at 04:07:37PM -0700, William D.Neumann wrote:
> On Mar 15, 2005, at 3:12 PM, Yoann Padioleau wrote:
> 
> >>To which, I'd assume the majority response would be, "So?"
> >
> >So some of his arguments are right. You make object "So?" but
> >we could continue a long moment that way.
> 
> Perhaps, perhaps not.  His point seems to be that programming in a 
> "functional style"[1] is inherently slower than an imperative style 
> because a list or a map have different performance characteristics than 
> do arrays.  To which the only response is along the lines of "True.  


Well, I tested the program with the original values for
columnSize and numRows as well as differet values.
I did not used the values that are mentioned in the posting
(7x3), because I had not too much time.

But with

  let columnSize = 5;;
  and with
  let numRows = 7;;

(look at the ";;" it seems he had used it in the toplevel... :))

and ocamlprof I got stuff like that:




================================================
(* checks if each cell in center colum is covered by an empty cell *)
let rec isCovered c1 c2 c3 =
  (* 2650588 *) let 
          memoized_isCovered = memoize3 isCovered_table isCovered 
  in 
  match (c1, c2, c3) with
   (* if center runs out of cells first, we are covered *)
        | (_, [], _) -> (* 501290 *) true
   (* if others run out first, we are not covered *)
        | ([], _, _) -> (* 0 *) false
        | (_, _, []) -> (* 0 *) false
   (* Empty followed by Planted in center colum
      skip this cell and next cell *)
        | ( (_::(_::rest1)), (Empty::(Planted::rest2)), (_::(_::rest3)) ) -> 
                (* 553730 *) true && ( isCovered rest1 rest2 rest3 )

        | ( (Empty::rest1), (_::rest2), (_::rest3) ) -> 
                (* 837698 *) true && ( isCovered rest1 rest2 rest3 )

        | ( (_::rest1), (_::rest2), (Empty::rest3) ) -> 
                  (* 291720 *) true && ( isCovered rest1 rest2 rest3 )

   (* Empty followed by Empty in center
      This cell is covered, but don't skip next cell *)
        | ( (_::rest1), (Empty::rest2), (_::rest3) ) -> 
                (* 297530 *) true && ( isCovered rest1 rest2 rest3 )
   (* this cell is covered by next cell *)
        | ( (_::rest1), (Planted::(Empty::rest2)), (_::rest3) ) -> 
                (* 99282 *) true && ( isCovered rest1 (Empty::rest2) rest3 )

   (* default:  we reach this if our current cell is not covered *)
        | (_, _, _) -> (* 69338 *) false;;
================================================


which does not really looks tail recursive.

Called more than 2 * 10^6 times...

And many other examples...


e.g. this one:

(* applies a list of functions to an argument *)
let rec applyFunctionList functions argument =
  (* 267386 *) match functions with
        | [] -> (* 9782 *) []
        | f::rest -> (* 257604 *) (f argument)::(applyFunctionList rest argument);; 

"only" called 267386 times, but when looking how the arguments
are used:  also applyFunctionList is not tail recursive...
...and even if called less than 10^6 times... it's a function that
creates a list in a non-tailrec way.

IMHO this is the reason, why the program performs so badly!

Ths stuff of tail recursion - even if it took a while
until I got it - was one of the first things on this list,
that people told me that it is necessary....

...but as a *real* C++ programmer it seems it is not necessary to learn...
...and better use the energy to tell all people how badly OCaml
performs!

Well... he performs badly in code-writing. :->

If he had read this mailing list, he wouls have seen that HE
(better: the code he wrote) is/was the problem, not OCaml itself. :)


Ciao,
   Oliver



^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 18:26           ` Kip Macy
@ 2005-03-16  0:32             ` Oliver Bandel
  2005-03-16 11:26             ` David Fox
  1 sibling, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-16  0:32 UTC (permalink / raw)
  To: caml-list

On Tue, Mar 15, 2005 at 10:26:06AM -0800, Kip Macy wrote:
> Most people who do things well are too busy doing them to have time to
> talk about them.


Yes, that's the reason, why the OCaml-core developers so seldom
talk to us here. The do not have the nervs to talk to us trolls. ;-)

I for myself again send my thanks to the OCaml developers...

...gasho!


Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 18:55         ` Christopher A. Watford
  2005-03-15 19:56           ` Jon Harrop
@ 2005-03-16  0:34           ` Oliver Bandel
  1 sibling, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-16  0:34 UTC (permalink / raw)
  To: caml-list

On Tue, Mar 15, 2005 at 01:55:07PM -0500, Christopher A. Watford wrote:
> On Tue, 15 Mar 2005 16:25:01 +0100 (CET), Christophe TROESTLER
> <debian00@tiscali.be> wrote:
> > I agree with that.  The ./ post is a typical
> > I-don't-know-what-I-am-talking-about-so-I-say-it-loud !  If he made a
> > point I believe it is that it's easier to hit the "send" key than to
> > try to be a good programmer...
> >
> ><SNIP>
> >
> > My 2¢,
> > ChriS
> 
> You're right, it looked something like this to me:
> 
> Hi! I'm new to OCaml, and my first attempt and making something like I
> would in C++ failed miserably. I didn't used standard library
> functions, because I didn't know they existed. I also went ahead and
> compiled things in a rediculously unoptimized fashion. Finally, I
> didn't bother comparing how my noobie code scaled against the C++.
> LIKE OMG OCAML SUX0R!
> 
> People post similar things for C#, PHP, any language really. Besides,
> it is VERY VERY simple to troll slashdot.


...but on the other side..... we can thank such posts,
because we had a nice evening and a theme to talk about... ;-)

So, we are not better... ? ;-)


Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 19:56           ` Jon Harrop
@ 2005-03-16  0:35             ` Oliver Bandel
  0 siblings, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-16  0:35 UTC (permalink / raw)
  To: caml-list

On Tue, Mar 15, 2005 at 07:56:12PM +0000, Jon Harrop wrote:
> On Tuesday 15 March 2005 18:55, Christopher A. Watford wrote:
> > On Tue, 15 Mar 2005 16:25:01 +0100 (CET), Christophe TROESTLER
> > You're right, it looked something like this to me:
> >
> > Hi! I'm new to OCaml, and my first attempt and making something like I
> > would in C++ failed miserably.
> 
> Perhaps this isn't the best forum to be saying this, but that guy's C++ code 
> sucked as well. It could have been a lot more concise and efficient if he'd 
> actually used C++...
> 
> Maybe the task will get on the shootout and we can do it properly in OCaml.
[...]

good idea. :)

Ciao,
   oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16  0:18                   ` Oliver Bandel
@ 2005-03-16  1:05                     ` Yoann Padioleau
  2005-03-16  2:55                       ` Oliver Bandel
  2005-03-16  3:01                     ` Jon Harrop
  1 sibling, 1 reply; 71+ messages in thread
From: Yoann Padioleau @ 2005-03-16  1:05 UTC (permalink / raw)
  To: Oliver Bandel; +Cc: caml-list

Oliver Bandel <oliver@first.in-berlin.de> writes:

> But with
> 
>   let columnSize = 5;;
>   and with
>   let numRows = 7;;
> 
> (look at the ";;" it seems he had used it in the toplevel... :))

And ? 
First, I dont think it is a good idea to make fun of people who try to use caml.
Second, many people I know still put ";;" cos they were taught that way
 (at the very beginning with caml-light I think you were forced to put those ";;", it
  became optional later, and habits are hard to change for many people :) )
Third, doing stuff at the toplevel is a good idea.

> which does not really looks tail recursive.
> 
> Called more than 2 * 10^6 times...
> 
> And many other examples...
> 
> 
> e.g. this one:
> 
> (* applies a list of functions to an argument *)
> let rec applyFunctionList functions argument =
>   (* 267386 *) match functions with
>         | [] -> (* 9782 *) []
>         | f::rest -> (* 257604 *) (f argument)::(applyFunctionList rest argument);; 
> 
> "only" called 267386 times, but when looking how the arguments
> are used:  also applyFunctionList is not tail recursive...
> ...and even if called less than 10^6 times... it's a function that
> creates a list in a non-tailrec way.
> 
> IMHO this is the reason, why the program performs so badly!

IMHO the reason it was slow is because it used associative list (instead of Map) 
for associative access,  and list of list (instead of array) for storing the grid.
I am not sure that making the function tail-recursive would have been the big
hit in this example.
I often transform my functions to make them tail-recursive because of stack overflow pb, not
that much because of speed pbs
(and many functions in the standard library are not tail-recursive, such as map)

> 
> Ths stuff of tail recursion - even if it took a while
> until I got it - was one of the first things on this list,
> that people told me that it is necessary....

I am not sure it is the first optimisation trick to give to a fresh ocaml programmer.

This tail-recursion stuff is one of the thing I hate the most with fp because it forces
you to change your code to adapt to the machine whereas it should be the 
inverse.
I don't understand why the compiler don't do himself those transformations.
Why is it so hard to take a non-tail-recursive-function and make it a tail-recursive-one ?



> 
> ...but as a *real* C++ programmer it seems it is not necessary to learn...
> ...and better use the energy to tell all people how badly OCaml
> performs!
> 
> Well... he performs badly in code-writing. :->

We all :) 
Each time I look at the code of someone else I find it awful, 
and each time a guy look at my code he has the same reaction.

> 
> If he had read this mailing list, he wouls have seen that HE
> (better: the code he wrote) is/was the problem, not OCaml itself. :)

If he had read this mailing list he would surely have stopped ocaml forever,
and this is not a compliment for the ocaml community.


Nevertheless, he has a little bit of a troll :)
He should have post his experience to the caml-list, to get a chance
to improve his code, instead of going directly to slashdot.

> 
> 
> Ciao,
>    Oliver
> 
> 
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
> 

-- 
Yoann  Padioleau,  INSA de Rennes, France   www.irisa.fr/prive/padiolea/
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**____   Get Free. Be Smart.  Simply use Linux and Free Software.   ____**


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 20:02     ` Yoann Padioleau
  2005-03-15 22:33       ` Richard Jones
@ 2005-03-16  1:33       ` YANG Shouxun
  1 sibling, 0 replies; 71+ messages in thread
From: YANG Shouxun @ 2005-03-16  1:33 UTC (permalink / raw)
  To: caml-list

On Wednesday 16 March 2005 04:02, Yoann Padioleau wrote:
> YANG Shouxun <yang.shx@fltrp.com> writes:
> > No. My experiments show that the OCaml implementation performs far better
> > than the C++ implementation when the column and row get larger:
>
> Perhaps because you are a liar.

I'm 100% sure I'm not a liar. I don't know what's the benefit of being a liar, 
nor the benefits of calling others a liar.

I checked and get the same results, though the figures are of course not 
exactly the same.

> > C++ is compiled with -O3, not sure what is the better optimization level,
> > while OCaml version (actually I used Sys.argv and references to the two
> > parameters) is compiled with ocamlopt
> >
> > 4x4 c++
> > real    0m0.003s
> > user    0m0.002s
> > sys     0m0.002s
> >
> > 4x4 ocaml
> > real    0m0.177s
> > user    0m0.137s
> > sys     0m0.001s
> >
> > 8x8 c++
> > real    0m8.703s
> > user    0m7.000s
> > sys     0m0.018s
> >
> > 8x8 ocaml
> > real    0m0.747s
> > user    0m0.485s
> > sys     0m0.002s
>
> I dont know where you get those numbers ?

As I said, the C++ version was compiled with "-O3" and the OCaml version with 
ocamlopt. The compiled programs were timed using "time garden_XXX x y" where 
XXX is either cpp for C++ version and ml for OCaml version.

I'm using Debian GNU/Linux, with g++ version 3.3.5 and ocamlopt version 
3.08.2. The computer is an Intel P4 2.40GHz with 256MB memory and 512KB cache 
and 506MB swap.

Below is what I got from the site of C++ version:
---8<---

#include <math.h>
#include <stdio.h>


enum cell{ Empty=0, Planted=1 }; 


int columnSize = 5;

int numStates;
cell **allStates;

int *allCosts;

// array indicating when a center column of cells is covered by
// the columns on either side of it.
// indexed as isCovered[c1][c2][c3]   true if c1 and c3 cover c2,
// or false otherwise
char ***isCoveredArray;


char isCovered( int inC1, int inC2, int inC3 ) {
    cell *c1 = allStates[ inC1 ];
    cell *c2 = allStates[ inC2 ];
    cell *c3 = allStates[ inC3 ];

    for( int i=0; i<columnSize; i++ ) {
        // test for a cell that is not covered and return false
        if( c2[i] == Planted &&
            c1[i] == Planted &&
            c3[i] == Planted ) {

            if( i <=0 || c2[i-1] == Planted ) {
                if( i >=columnSize-1 || c2[i+1] == Planted ) {

                    return false;
                    }
                }
            }
        }

    // else all covered
    return true;
    }


void printState( int inStateIndex ) {
    cell *state = allStates[ inStateIndex ];

    for( int i=0; i<columnSize; i++ ) {
        if( state[i] == Empty ) {
            printf( "O" );
            }
        else {
            printf( "X" );
            }
        }
    printf( "\n" );
    }


struct costStatePair {
        int cost;
        // the index in the allStates array
        int stateIndex;
    };


// table for memoizing optLayout
struct costStatePair ***optLayoutTable;



// place where optLayout results are returned
struct costStatePair optLayoutResult;

/**
 * Computes the optimum layout for a given number of columns given
 * states for the first two columns.
 *
 * @param inNumColumns the number of columns.  Must be at least 3.
 * @param inFirstColumnStateIndex the index of the state (in allStates)
 *   of the first column.
 * @param inSecondColumnStateIndex the index of the state (in allStates)
 *   of the second column.
 *
 * @return result is set in the optLayoutResult structure and returned.
 *   Thus, this call is NOT threadsafe.   
 */
struct costStatePair optLayout( int inNumColumns, int inFirstColumnStateIndex,
                                int inSecondColumnStateIndex ) {

    int c = inNumColumns-1;
    if( optLayoutTable[c]
                      [inFirstColumnStateIndex]
                      [inSecondColumnStateIndex].cost != -1 ) {
        // already have this result
        return optLayoutTable[c]
                             [inFirstColumnStateIndex]
                             [inSecondColumnStateIndex];
        }
    
    if( inNumColumns < 3 ) {
        optLayoutResult.cost =
            allCosts[ inFirstColumnStateIndex ] +
            allCosts[ inSecondColumnStateIndex ];
        optLayoutResult.stateIndex = -1;


        // save in table
        optLayoutTable[c]
            [inFirstColumnStateIndex]
            [inSecondColumnStateIndex].cost = optLayoutResult.cost;
        optLayoutTable[c]
            [inFirstColumnStateIndex]
            [inSecondColumnStateIndex].stateIndex = 
optLayoutResult.stateIndex;
        
        
        return optLayoutResult;
        }
            
    
    
    int bestCost = inNumColumns * columnSize + 1;
    int bestStateIndex = -1;

    // examin all possible states for the third column
    for( int i=0; i<numStates; i++ ) {

        // if i does its part to cover our second column
        if( isCovered( inFirstColumnStateIndex,
                       inSecondColumnStateIndex, i ) ) {

            char iCovered = false;
            
            int costOfRest = 0;
            if( inNumColumns > 3 ) {
                struct costStatePair result =
                    optLayout( inNumColumns - 1,
                               inSecondColumnStateIndex,
                               i );
                costOfRest = result.cost -
                    allCosts[ inSecondColumnStateIndex ];

                // optLayout will only pick a 3rd column that helps to
                // cover i
                iCovered = true;
                }
            else {
                // just the cost of i by itself
                costOfRest = allCosts[i];

                // make sure that i is covered by inSecondColumnStateIndex
                // put the all-planted column (0) on the other side of i
                iCovered = isCovered( inSecondColumnStateIndex, i, 0 );
                }

            if( iCovered && costOfRest < bestCost ) {
                bestCost = costOfRest;
                bestStateIndex = i;
                }
            }
        }
    
    optLayoutResult.cost = bestCost +
        allCosts[ inFirstColumnStateIndex ] +
        allCosts[ inSecondColumnStateIndex ];
    
    optLayoutResult.stateIndex = bestStateIndex;


    // save in table
    optLayoutTable[c]
        [inFirstColumnStateIndex]
        [inSecondColumnStateIndex].cost = optLayoutResult.cost;
    optLayoutTable[c]
        [inFirstColumnStateIndex]
        [inSecondColumnStateIndex].stateIndex = optLayoutResult.stateIndex;

    
    return optLayoutResult;
    }




void printOptLayout( int inNumColumns ) {
    // find best starting state for 10 columns by
    // running optLayout on 11 columns
    int bestFirstColumn = -1;
    int bestSecondColumn = -1;
    int bestCost = (inNumColumns+1) * columnSize + 1;

    
    
    for( int i=0; i<numStates; i++ ) {
        // state 0 is the all-planted state
        struct costStatePair result = optLayout( inNumColumns+1, 0, i );

        if( result.cost < bestCost ) {
            bestFirstColumn = i;
            bestSecondColumn = result.stateIndex;
            bestCost = result.cost;            
            }
        //printf( "best cost = %d\n", bestCost );
        }

    printf( "%d empty cells:\n", bestCost );
    printState( bestFirstColumn );
    printState( bestSecondColumn );
    
    for( int c=inNumColumns; c>=3; c-- ) {

        struct costStatePair restult =
            optLayout( c, bestFirstColumn, bestSecondColumn );
        
        printState( restult.stateIndex );

        bestFirstColumn = bestSecondColumn;
        bestSecondColumn = restult.stateIndex;
        }
    }






int main( int inNumArgs, char **inArgs ) {

    int numColumns = 10;

    if( inNumArgs > 1 ) {
        sscanf( inArgs[1], "%d", &columnSize );
        }
    if( inNumArgs > 2 ) {
        sscanf( inArgs[2], "%d", &numColumns );
        }
    
    
    numStates = (int)( pow( 2, columnSize ) );
    allStates = new cell*[ numStates ];
    allCosts = new int[ numStates ];


    
    
    
    int i, j, k;
    for( i=0; i<numStates; i++ ) {

        allCosts[i] = 0;

        allStates[i] = new cell[ columnSize ];
        for( int b=0; b<columnSize; b++ ) {

            if( ( ( i >> b ) & 0x1 ) == 1 ) {
                allStates[i][b] = Empty;
                allCosts[i] ++;
                }
            else {
                allStates[i][b] = Planted;
                }
            }
        }

    int numEntries = 0;
    optLayoutTable = new struct costStatePair **[numColumns +1];
    int c;
    for( c=0; c<numColumns+1; c++ ) {
        optLayoutTable[c] = new struct costStatePair *[numStates];
        for( int i=0; i<numStates; i++ ) {
            optLayoutTable[c][i] = new struct costStatePair[ numStates ];

            for( int j=0; j<numStates; j++ ) {
                optLayoutTable[c][i][j].cost = -1;
                optLayoutTable[c][i][j].stateIndex = -1;

                numEntries ++;
                }
            }            
        }
    printf( "Done constructing memoization table with %d entries\n",
            numEntries );
    
    /*
    isCoveredArray = new char**[ numStates ];
    for( i=0; i<numStates; i++ ) {
        isCoveredArray[i] = new char*[numStates];
        for( j=0; j<numStates; j++ ) {
            isCoveredArray[i][j] = new char[numStates];
            for( k=0; k<numStates; k++ ) {
                isCoveredArray[i][j][k] = isCovered( i, j, k );
                }
            }
        }
    */

    /*
    for( i=0; i<numStates; i++ ) {
        for( j=0; j<numStates; j++ ) {
            delete [] isCoveredArray[i][j];
            }
        delete [] isCoveredArray[i];
        }
    delete [] isCoveredArray;
    */



    for( c=2; c<=numColumns; c++ ) {
        printf( "\n%d by %d\n", columnSize, c );

        printOptLayout( c );
        }

    
    


    for( c=0; c<numColumns+1; c++ ) {
        
        for( int i=0; i<numStates; i++ ) {
            delete [] optLayoutTable[c][i];
            }
        delete [] optLayoutTable[c];    
        }
    delete [] optLayoutTable;
    
    for( i=0; i<numStates; i++ ) {
        delete [] allStates[i];
        }
    delete [] allStates;
    delete [] allCosts;
    
    return 0;
    }

---8<---

The original OCaml version:

---8<---
(* Computes optimal garden layouts using dynamic programming*)

(* the width of a state in our dynamic programming table *)
(* the algorithm will run in O( 2^columnSize ) time *)
let columnSize = 4;;

(* How many rows to compute solutions for *)
let numRows = 10;;


(* generate all possible states for columns of height h *)
type cell = Empty 
       | Planted;;
    

let printCell c =
  match c with
 | Empty   -> "O"
 | Planted -> "X";;


let rec printCells cs = 
  match cs with
 | []        -> ""
 | (c::rest) -> (printCell c) ^ (printCells rest);;


let rec printStates states =
  match states with
 | []        -> ""
 | (s::[])   -> printCells s
 | (s::rest) -> (printCells s) ^ " " ^ (printStates rest);;



(* apply f to every element of list *)
let rec map f list =
  match list with
 | []      -> []
 | x::rest -> (f x) :: (map f rest);;



let rec generateStates numStates =
  match numStates with 
 | 0 -> [[]]
 | h ->
  let 
   shorterStates = generateStates (h-1) and
   prepend c s = c::s
  in
    ( map ( prepend Empty ) shorterStates ) @
    ( map ( prepend Planted ) shorterStates );;



let allStates = generateStates columnSize;;

let rec genIndexList currentIndex maxIndex =
  if( currentIndex <= maxIndex ) 
  then currentIndex :: ( genIndexList (currentIndex+1) maxIndex )
  else [];;


let rec length list =
  match list with
 | []      -> 0
 | x::rest -> 1 + length rest;;


let stateIndices = genIndexList 0 ((length allStates) - 1);;


let rec findIndexRec s states startIndex =
 match states with
   | []      -> -1
   | (x::xs) ->
    if( s = x ) then startIndex
    else findIndexRec s xs (startIndex+1);;

let findIndex s = findIndexRec s allStates 0;;
  
 


let rec generateSolidState length cellValue =
  match length with 
 | 0 -> []
 | x -> cellValue::(generateSolidState (x-1) cellValue );;

let allPlantedState = generateSolidState columnSize Planted;;
let allEmptyState = generateSolidState columnSize Empty;;


(* computes the min cost pair in a list of cost-state pairs *)
let rec minCost pairs =
  match pairs with
 | []          -> ( 100000, allEmptyState )  (* error *)
 | (c,s)::[]   -> (c,s)
 | (c,s)::rest ->
  let
   ( minCostRest, minStateRest ) = minCost rest
  in
    if( c < minCostRest ) then (c,s)
    else ( minCostRest, minStateRest );;

(* computes the min cost pair in a list of cost-state-state triples *)
let rec minCost3 triples =
  match triples with
 | []          -> ( 100000, allEmptyState, allEmptyState )  (* error *)
 | (c,s1,s2)::[]   -> (c,s1,s2)
 | (c,s1,s2)::rest ->
  let
   ( minCostRest, minState1Rest, minState2Rest ) = minCost3 rest
  in
    if( c < minCostRest ) then (c,s1,s2)
    else ( minCostRest, minState1Rest, minState2Rest );;


(* adds c to the cost of the minimum-cost pair in a list *)
let addToMin c pairList = 
  let (minC, minS) = minCost pairList in
 (c + minC, minS );;
 


(* computes the cost of a state*)
let rec cost state =
  match state with
 | []  -> 0
 | Empty::rest -> 1 + cost rest
 | Planted::rest -> cost rest;;
    
let costList = map cost allStates;;


(* Set up an associative list for memoization *)
let lookup key table = List.assoc key !table;;
let insert key value table = table := (key, value) :: !table;;


(* memoize any 3-parameter function *)
let memoize3 table f x y z =
    try
        lookup (x,y,z) table
    with
    | Not_found ->
        let result = f x y z in
        insert (x, y, z) result table;
        result;;

(* table for memoizing optLayout *)
let isCovered_table = ref [];;

(* checks if each cell in center colum is covered by an empty cell *)
let rec isCovered c1 c2 c3 =
  let 
   memoized_isCovered = memoize3 isCovered_table isCovered 
  in 
  match (c1, c2, c3) with
   (* if center runs out of cells first, we are covered *)
 | (_, [], _) -> true
   (* if others run out first, we are not covered *)
 | ([], _, _) -> false
 | (_, _, []) -> false
   (* Empty followed by Planted in center colum
      skip this cell and next cell *)
 | ( (_::(_::rest1)), (Empty::(Planted::rest2)), (_::(_::rest3)) ) -> 
  true && ( isCovered rest1 rest2 rest3 )
 
 | ( (Empty::rest1), (_::rest2), (_::rest3) ) -> 
  true && ( isCovered rest1 rest2 rest3 )

 | ( (_::rest1), (_::rest2), (Empty::rest3) ) -> 
    true && ( isCovered rest1 rest2 rest3 )

   (* Empty followed by Empty in center
      This cell is covered, but don't skip next cell *)
 | ( (_::rest1), (Empty::rest2), (_::rest3) ) -> 
  true && ( isCovered rest1 rest2 rest3 )
   (* this cell is covered by next cell *)
 | ( (_::rest1), (Planted::(Empty::rest2)), (_::rest3) ) -> 
  true && ( isCovered rest1 (Empty::rest2) rest3 )

   (* default:  we reach this if our current cell is not covered *)
 | (_, _, _) -> false;;


let memoized_isCovered = memoize3 isCovered_table isCovered;;

(*

-- this is a lazy array of arrays of arrays.
-- first index is number of columns (-1... so 1 colum result is
--   at index 0
-- Second index is the state index (an index into allStates).  This
--    is the state of the first column
-- Third index is the state index (an index into allStates).  This
--    is the state of the column before the first column
-- So, first dimension is infinite, while second and third dimensions are
-- finite.
optSolutionArray = [  list2 | 
       f <- (map optLayout [1..]), 
       list <- [ map f stateIndices ], 
                      list2 <- [
        [ map f2 stateIndices | f2 <- list ] 
          ]
       ]

-- lazy array memoizing isCovered
isCoveredArray = [  list2 | 
     f <- (map isCovered allStates), 
     list <- [ map f allStates ], 
                    list2 <- [
         [ map f2 allStates | f2 <- list ] 
        ]
     ]
*)

(* applies a list of functions to an argument *)
let rec applyFunctionList functions argument =
  match functions with
 | [] -> []
 | f::rest -> (f argument)::(applyFunctionList rest argument);; 


exception Length_mismatch__makeTriples;;

let rec makeTriples listOfPairs listOfSingles =
  match (listOfPairs, listOfSingles) with
 | ([],[]) -> []
 | ((p1,p2)::pRest, s::sRest) -> (p1,p2,s)::(makeTriples pRest sRest)
 | _ -> raise Length_mismatch__makeTriples;;  


(* discard middle element of each triple *)
let rec discardMiddle listOfTriples =
  match listOfTriples with
 | [] -> []
 | (t1,_,t3)::tRest -> (t1,t3)::(discardMiddle tRest);;


let rec filterTriples f list =
  match list with
 | [] -> []
 | (x,y,z)::rest -> 
  if( f x y z ) then (x,y,z)::( filterTriples f rest )
  else filterTriples f rest;;

let rec filter f list =
  match list with
 | [] -> []
 | x::rest -> 
  if( f x ) then x::( filter f rest )
  else filter f rest;;



(* Simple memo fib *)
(*
let rec fib = function
    | 0 -> 0
    | 1 -> 1
    | n -> memo_fib (n-1) + memo_fib (n-2)
and memo_fib n = memoize fib n;;
*)

(* table for memoizing optLayout *)
let optLayout_table = ref [];;


(*
-- computes the optimum layout of i columns given that the first column
-- has state s and the column before the first column has state s1 
-- Ensures that first colum (s) is covered by s1 and the optimal solution
--   to the remaining colums.  Does not ensure that s1 is covered (since
--   s is fixed, this function has no control over the coverage of s1). *)
let rec optLayout numColumns s s1 =
  (*print_string "Working on optLayout ";
  print_int numColumns;
  print_string (" s=" ^ (printCells s));
  print_string (" s1=" ^ (printCells s1));
  print_newline ();
  *)
  match numColumns with
 | 1 -> ( cost s, allPlantedState )
 | i ->
  let 
   memoized_optLayout = memoize3 optLayout_table optLayout
  in
  (* so much cleaner with list comprehensions
    addToMin ( cost s )
     [ (c,s2) |
     s2 <- allStates, 
     (c,s3) <- [ optLayout (i-1) s2 s ],
     isCovered s s2 s3,
     isCovered s1 s s2 ]
  *)
  let 
   removeUncoveredS2 s2 = (isCovered s1 s s2)
  in
  let
   allGoodStates = List.filter removeUncoveredS2 allStates 
  in
  let
   (* (opt i-1) applied to all states, a list of
      functions waiting to be applied to s *)
   optAppliedToAllStates = 
           List.map (memoized_optLayout (i-1)) allGoodStates
  in
  let
   (* these are all optimal pairs for all choices of s2 *)
   optAppliedToAllS2 = applyFunctionList optAppliedToAllStates s
  in
  let
   (* triples of (c,s3,s2) *)
   optC_S3_S2 = makeTriples optAppliedToAllS2 allGoodStates
  in
  let
   (* a filter function to remove uncovered triples from our list *)
   removeUncovered (c, s3, s2) = (isCovered s s2 s3)  (*&& 
                                (isCovered s1 s s2)*)
  in
  let
   covered_optC_S3_S2 = List.filter removeUncovered optC_S3_S2
  in

  let
   (minC, minS3, minS2) = minCost3 covered_optC_S3_S2
  in
    ( (cost s) + minC, minS2 )
  
(*
-- look up result in optSolutionArray instead of computing
-- This memoization dramatically speeds up computation
-- And hey... it was very elegant to express this in Haskell
memoizedOptLayout 1 s s1 = optLayout 1 s s1
memoizedOptLayout i s s1 = optSolutionArray !! (i-1) !! s !! s1 
*)

let memoized_optLayout = memoize3 optLayout_table optLayout;;


(* computes the first column of the optimum x-column layout *)
let computeOpt x =
    (* force an extra planted column before the first column
       force an extra empty colum before that *)
  optLayout (x + 1) allPlantedState allEmptyState;;


let rec printOptGivenState numColumns s s1 = 
  match numColumns with
 | 1 -> printCells s
 | x ->
  let 
   (c, optNextState) = optLayout x s s1
  in
    ( printCells s ) ^ "\n" ^ 
   printOptGivenState (x - 1) optNextState s;;
  

(* hey... it actually works!
 this is the main function *)
let printOpt x =
  let
   (c, optStartingState) = computeOpt x
  in
 print_int c;
 print_string 
   (" empty cells:\n" ^ 
   printOptGivenState x optStartingState allPlantedState );;

let main () = 
  (* first, fill up the memo table *)
(*
  for i=1 to 10 do
 print_string( "Filling table row " );
 print_int( i );
 print_newline();
 List.map 
   (applyFunctionList ( List.map (memoized_optLayout i) allStates )) 
   allStates;
    print_string( "   done with table row " );
 print_int( i );
 print_newline();
  done;
*)
  for i = 2 to numRows do
 print_int( columnSize );
 print_string( " by " );
 print_int( i );
 print_newline();
 printOpt i;
 print_newline();
 print_newline();
  done;;

main ();;

---8<---

Since I don't want to change the source code and recompile each time I want to 
pass a different argument list, I made the following changes, without 
handling some possible exceptions:

---8<---
--- Garden.ml   2005/03/15 09:38:16     1.1
+++ Garden.ml   2005/03/16 01:22:08
@@ -2,10 +2,10 @@

 (* the width of a state in our dynamic programming table *)
 (* the algorithm will run in O( 2^columnSize ) time *)
-let columnSize = 4;;
+let columnSize = ref 4;;

 (* How many rows to compute solutions for *)
-let numRows = 10;;
+let numRows = ref 10;;


 (* generate all possible states for columns of height h *)
@@ -54,7 +54,7 @@



-let allStates = generateStates columnSize;;
+let allStates = generateStates !columnSize;;

 let rec genIndexList currentIndex maxIndex =
   if( currentIndex <= maxIndex )
@@ -88,8 +88,8 @@
        | 0 -> []
        | x -> cellValue::(generateSolidState (x-1) cellValue );;

-let allPlantedState = generateSolidState columnSize Planted;;
-let allEmptyState = generateSolidState columnSize Empty;;
+let allPlantedState = generateSolidState !columnSize Planted;;
+let allEmptyState = generateSolidState !columnSize Empty;;


 (* computes the min cost pair in a list of cost-state pairs *)
@@ -372,7 +372,7 @@

 let main () =
   (* first, fill up the memo table *)
-(*
+  (*
   for i=1 to 10 do
        print_string( "Filling table row " );
        print_int( i );
@@ -385,8 +385,11 @@
        print_newline();
   done;
 *)
-  for i = 2 to numRows do
-       print_int( columnSize );
+  let len = Array.length Sys.argv in
+    if len > 1 then columnSize := int_of_string (Sys.argv.(1));
+    if len > 2 then numRows := int_of_string (Sys.argv.(2));
+  for i = 2 to !numRows do
+       print_int( !columnSize );
        print_string( " by " );
        print_int( i );
        print_newline();
---8<---

> I tried the code of the "troll" and the ocaml version performs far _worse_
> than the c++ implementation when the column and row get larger.
>
> > 12x12 c++
> > the process was killed by the OS
> >
> > 12x12 ocaml
> > real    0m1.210s
> > user    0m0.886s
> > sys     0m0.001s

I admit I didn't look into the C++ or OCaml code yet, but that's not what I'm 
trying to say here.

Everybody is welcome to point out where I might be mistaken in producing the 
incredible results (at least to Yoann Padioleau) and confirm whether the 
experiments can be repeated or not.


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 21:03           ` padiolea
  2005-03-15 21:40             ` William D.Neumann
@ 2005-03-16  1:38             ` Jacques Garrigue
  1 sibling, 0 replies; 71+ messages in thread
From: Jacques Garrigue @ 2005-03-16  1:38 UTC (permalink / raw)
  To: padiolea; +Cc: caml-list

Well, since it seems difficult to hide that I'm an anonymous coward,
I add a few comments for the list.

From: padiolea@irisa.fr
> Yes but this ocaml code use array ?
> In that case it supports what the "troll" said, that is
> the resulting code is no more "functionnal".
> I agree with eijro sumii that ocaml is not just about functionnal
> programming but in the mind of many people advocating ocaml is advocating
> functionnal programming.
> 
> I think the way to answer to those trolls is to teach them the way
> to do, in that case to use Map instead of associative list, and
> not to be pretentious and to tell that he is just a newbie.
> He is not a newbie, this garden optimization problem is not that simple.

In this particular case, I believe the trouble is rather that the
problem is really geared toward a specific solution. Efficient
memoization requires efficient access to memoized results, which in
this case can be obtained by mapping states to integers. And there
happens to be a trivial mapping. Then any solution will have to
iterate on the states.

If you look at my translation, I do not mutate arrays (except for
memoization), and use no references. That is, the mapping from states
to integers is actually produced in a purely functional way, and
arrays are only there to provide O(1) access. Moreover state
representation uses lists and natural sharing, so that it is
reasonably space efficient.
I also use lists, pattern matching, and recursion, so I believe this
fulfills his requirement about being written in functional style.

Out of curiosity, I also wrote a purely functional version, where
memoizing is done through an array of lazy values.
  http://wwwfun.kurims.kyoto-u.ac.jp/~garrigue/garden3.ml
The code is actually slightly shorter. Performance is rather close.
On a Pentium M 1.8, for a 8x8 garden, I obtain (including memory usage)
   Garden.cpp  5.8s  6.1MB (g++ -O)
   Garden.cpp  4.5s  6.2MB (g++ -O3)
   garden2.ml  5.9s  8.3MB (ocamlopt)
   garden3.ml  10s   27.4MB (ocmalopt)
So you can see that garden2, while being almost purely functional,
is really equivalent in performance to his C++ code (which is a bit
dumb, but garden2 doesn't try to be more clever), while garden3 uses
more memory (as expected).

The only thing this example shows is that writing in a functional
language doesn't dispense you of doing a complexity analysis. In
particular the use of structural equality and association lists may
cost a lot in practice.
Some people may have a mystical belief that the compiler will
automatically improve your code through program transformation, but at
least in ocaml the situation is simple: the compiler does no
transformation whatsoever, so you get what you write.
And of course, SICP is a good reading before starting to write
in a functional programming language; I suppose all the structures I
used are explained there in detail.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16  1:05                     ` Yoann Padioleau
@ 2005-03-16  2:55                       ` Oliver Bandel
  2005-03-16 11:23                         ` Thomas Fischbacher
  2005-03-16 13:33                         ` Yoann Padioleau
  0 siblings, 2 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-16  2:55 UTC (permalink / raw)
  To: caml-list

On Wed, Mar 16, 2005 at 02:05:43AM +0100, Yoann Padioleau wrote:
> Oliver Bandel <oliver@first.in-berlin.de> writes:
> 
> > But with
> > 
> >   let columnSize = 5;;
> >   and with
> >   let numRows = 7;;
> > 
> > (look at the ";;" it seems he had used it in the toplevel... :))
> 
> And ? 

Only nice to see.
Nothing more. ;-)

It's only that I think about it, because he
talks with seemingly bad intentions about OCaml.
(a kind of C++ dogmatism)


> First, I dont think it is a good idea to make fun of people who try to use caml.

I don't do that.

But I can't see that there is really an interest in exploring OCaml.
If he only would be cynic about "well I tried it, but it has proven
it's a crap language... but I give you (experienced OCaml programmers)
the chance to show me that it isn't bad (and *I* have o learn the language)"
then this woul be ok.

But it seems that he's saying: "well, OCaml never can compete with C++".

Maybe I'm wrong here and he's a good guy. But IMHO it seems he's looking
for proved Ocaml-failure (and not for "well, I tried it, it seems OCaml sucks,
but please tell me it does not!", which I could accept).




> Second, many people I know still put ";;" cos they were taught that way

Hey, that was the way I started too! :)

That comment from me only shows: Well, it seems he's an absolute beginner.

To be a beginner is not wrong. It's good!
To be a beginner every day and every time means: to be open for new
things every time!
That's good! :)

But as stated above: Would be nice if the OCaml-bashing would contain at least
a bit of "maybe I'm wrong, and I only use cynism, because I thaught it
performed better (or It's easier to learn).

Maybe I've overlooked that positive-thinking approach behind
his harsh words?!


>  (at the very beginning with caml-light I think you were forced to put those ";;", it
>   became optional later, and habits are hard to change for many people :) )
> Third, doing stuff at the toplevel is a good idea.

Yes.

So, what are we talking about?

Do you think *I'm the bad guy*?!

"mea culpa" ?!!!????


> 
> > which does not really looks tail recursive.
> > 
> > Called more than 2 * 10^6 times...
> > 
> > And many other examples...
> > 
> > 
> > e.g. this one:
> > 
> > (* applies a list of functions to an argument *)
> > let rec applyFunctionList functions argument =
> >   (* 267386 *) match functions with
> >         | [] -> (* 9782 *) []
> >         | f::rest -> (* 257604 *) (f argument)::(applyFunctionList rest argument);; 
> > 
> > "only" called 267386 times, but when looking how the arguments
> > are used:  also applyFunctionList is not tail recursive...
> > ...and even if called less than 10^6 times... it's a function that
> > creates a list in a non-tailrec way.
> > 
> > IMHO this is the reason, why the program performs so badly!
> 
> IMHO the reason it was slow is because it used associative list (instead of Map) 
> for associative access,

Maybe it is.
I don't say it is *not*.

I have not loked into the code in so much detail
that I could see that the associative map is the problem
or is not.
If the list is short, an associative list may not perform so badly.
(Correct me, if I'm wrong.)

But IMHO creating the environment for a function that is non tail-rec
needs more ressources than using assoc-lists ionstead of maps
in that application (Correct me, if I'm wrong).

(And maybe - if it is always the case - that all depends on
the amount of data/how often functions are called and so on.



> and list of list (instead of array) for storing the grid.

Yes, that also seems to be a problem.


> I am not sure that making the function tail-recursive would have been the big
> hit in this example.

But as long as nobody tried it / analzed it, your assumption is
only an assumption, as my assumption is only an assumotion too!


... IMHO it makes sense in a field where THE solution is not
already known, to come out with ideas that are *possibly*
solutions to a problem.

So, nothing else is "use map instead of..."  and "use arrays instead of...".


The real freaks doesn't post to that thread, as it maybe is trivial to them,
to talk about that stuff...?!



> I often transform my functions to make them tail-recursive because of stack overflow pb, not
> that much because of speed pbs
> (and many functions in the standard library are not tail-recursive, such as map)


Well, maybe I have overestimated the tailrec-point,
but as long as there is not a proven counter-example,
the opposite of what I stated seems to be only an assumption too.

Maybe such freaks like the OCaml core-team, or M.Mottl will
see in milliseconds what is going on... but the whole thread
on slashdot (and here) seems to be guessing from many people.

If I'm wrong, please show me.

!!! To see different results it would be nice to have different implementations
!!! to compare them all!


> 
> > 
> > Ths stuff of tail recursion - even if it took a while
> > until I got it - was one of the first things on this list,
> > that people told me that it is necessary....
> 
> I am not sure it is the first optimisation trick to give to a fresh ocaml programmer.

That is a thing what special studied computer science people 
gave me as one of the first hints on that list.
(And wehen looking in SICP, it seems, that it's very necessary to think
abot it in more detail.)


Would be interesting to have different variations of the
code, using different ways of coding some special tasks
in different ways.... and maybe oe implementation,
that uses *all* suggestions.

To do it in the language shootout, as on Jon stated it, seems
to be a veryg good idea.


> 
> This tail-recursion stuff is one of the thing I hate the most with fp because it forces
> you to change your code to adapt to the machine whereas it should be the 
> inverse.

But only because you hate it does not mean that changing the code will not result
in better performance.

At least for that list-creating stuff I have (e.g. reading in a file
and write it to a list of lines) I have seen the advantages (in speed!)
when using tailrec versions or imperative versions) instead of
simple recursion.

And some of that troll-code's functions are really doing that!
Build lists by building lists non-tailrec.


> I don't understand why the compiler don't do himself those transformations.

Well I understand, why a compile does not do that job: because it's
too complicate for a programmer of a compiler to implement that feature. ;-)

But on the other side I think the same: Why not implementing such stuff directly
into the compiler?! Would be nice...

(... or not, because we never would think about what we are doing then...)



> Why is it so hard to take a non-tail-recursive-function and make it a tail-recursive-one ?

It's not hard, it's only "practise, practise, practise" or
"exercise, exercise, exercise..." ;-)



One of the people on this list once shwed a way of how to change a loop
into tailrevc-stuff in general (shown for two or three args of a func).

(Remi Vacant?!).

Maybe I have somewhere a printed page of it and can look for it / find it...



Ciao,
   Oliver


P.S.: Well... too much beer this night... :(



^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16  0:18                   ` Oliver Bandel
  2005-03-16  1:05                     ` Yoann Padioleau
@ 2005-03-16  3:01                     ` Jon Harrop
  2005-03-16 13:10                       ` Yoann Padioleau
  1 sibling, 1 reply; 71+ messages in thread
From: Jon Harrop @ 2005-03-16  3:01 UTC (permalink / raw)
  To: caml-list


Just for the record, I'd like to dispell a couple of myths:

On Wednesday 16 March 2005 01:05, Yoann Padioleau wrote:
> IMHO the reason it was slow is because it used associative list (instead of
> Map) for associative access,

Although Map is asymptotically faster than List.assoc for lookup (O(ln n) vs 
O(n)), OCaml's Hashtbl and array-based equivalents are typically several 
times faster than Map.

Also, I think that many people would consider the use of an imperative data 
structure, such as a hash table, for memoizing to be the remit of functional 
programming.

On Wednesday 16 March 2005 00:18, Oliver Bandel wrote:
> which does not really looks tail recursive.
> Called more than 2 * 10^6 times...
> And many other examples...

In OCaml, non-tail-recursive functions are often faster than their tail 
recursive equivalents for small inputs (e.g. short lists). I expect that the 
functions you have identified fall into this category, so converting them to 
tail-recursive form is likely to slow the program down rather than speed it 
up.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16  2:55                       ` Oliver Bandel
@ 2005-03-16 11:23                         ` Thomas Fischbacher
  2005-03-16 23:41                           ` Oliver Bandel
  2005-03-16 13:33                         ` Yoann Padioleau
  1 sibling, 1 reply; 71+ messages in thread
From: Thomas Fischbacher @ 2005-03-16 11:23 UTC (permalink / raw)
  To: Oliver Bandel; +Cc: caml-list


On Wed, 16 Mar 2005, Oliver Bandel wrote:

> > Second, many people I know still put ";;" cos they were taught that way
> 
> Hey, that was the way I started too! :)

I should say, I do it *on purpose*, even knowing that it is not necessary.

Why? Putting ";;" or not does not make a difference for the programmer, 
but not using certain "syntax quirks" makes it easier to operate on the 
source code with tools, quite in general.

-- 
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)


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 18:26           ` Kip Macy
  2005-03-16  0:32             ` Oliver Bandel
@ 2005-03-16 11:26             ` David Fox
  1 sibling, 0 replies; 71+ messages in thread
From: David Fox @ 2005-03-16 11:26 UTC (permalink / raw)
  To: Kip Macy
  Cc: Thomas Fischbacher, Christophe TROESTLER, O'Caml Mailing List

[-- Attachment #1: Type: text/plain, Size: 2001 bytes --]

That is sad too.

Kip Macy wrote:

>Most people who do things well are too busy doing them to have time to
>talk about them.
>
>     -Kip
>
>
>On Tue, 15 Mar 2005 19:05:10 +0100 (CET), Thomas Fischbacher
><Thomas.Fischbacher@physik.uni-muenchen.de> wrote:
>  
>
>>On Tue, 15 Mar 2005, Christophe TROESTLER wrote:
>>
>>    
>>
>>>I agree with that.  The ./ post is a typical
>>>I-don't-know-what-I-am-talking-about-so-I-say-it-loud !  If he made a
>>>point I believe it is that it's easier to hit the "send" key than to
>>>try to be a good programmer...
>>>      
>>>
>>Isn't it sad that those people generate so much more noise than those who
>>know how to program and really do cool stuff with ocaml?
>>
>>--
>>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)
>>
>>_______________________________________________
>>Caml-list mailing list. Subscription management:
>>http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
>>Archives: http://caml.inria.fr
>>Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>>Bug reports: http://caml.inria.fr/bin/caml-bugs
>>
>>    
>>
>
>_______________________________________________
>Caml-list mailing list. Subscription management:
>http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
>Archives: http://caml.inria.fr
>Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>Bug reports: http://caml.inria.fr/bin/caml-bugs
>  
>

--

This message contains information which may be confidential and privileged. Unless you are the 
addressee (or authorized to receive for the addressee), you may not use, copy or disclose to anyone 
the message or any information contained in the message. If you have received the message in error, 
please advise the sender and delete the message.  Thank you.

[-- Attachment #2: Type: text/html, Size: 3239 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16  3:01                     ` Jon Harrop
@ 2005-03-16 13:10                       ` Yoann Padioleau
  2005-03-16 13:41                         ` Jacques Garrigue
  0 siblings, 1 reply; 71+ messages in thread
From: Yoann Padioleau @ 2005-03-16 13:10 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

Jon Harrop <jon@ffconsultancy.com> writes:

> Just for the record, I'd like to dispell a couple of myths:
> 
> On Wednesday 16 March 2005 01:05, Yoann Padioleau wrote:
> > IMHO the reason it was slow is because it used associative list (instead of
> > Map) for associative access,
> 
> Although Map is asymptotically faster than List.assoc for lookup (O(ln n) vs 
> O(n)), OCaml's Hashtbl and array-based equivalents are typically several 
> times faster than Map.

I agree, I beleived that too but 
I switched from Map to Hashtbl in the "troll" code and Hashtbl sux. 
I don't know why.

> Also, I think that many people would consider the use of an imperative data 
> structure, such as a hash table, for memoizing to be the remit of functional 
> programming.

I do. As much as possible I try to have "persistent" (persistent in the okasaki sense)
data-structures.


> 
> On Wednesday 16 March 2005 00:18, Oliver Bandel wrote:
> > which does not really looks tail recursive.
> > Called more than 2 * 10^6 times...
> > And many other examples...
> 
> In OCaml, non-tail-recursive functions are often faster than their tail 
> recursive equivalents for small inputs (e.g. short lists). 

really ? why ?

> I expect that the 
> functions you have identified fall into this category, so converting them to 
> tail-recursive form is likely to slow the program down rather than speed it 
> up.

-- 
Yoann  Padioleau,  INSA de Rennes, France   www.irisa.fr/prive/padiolea/
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**____   Get Free. Be Smart.  Simply use Linux and Free Software.   ____**


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16  2:55                       ` Oliver Bandel
  2005-03-16 11:23                         ` Thomas Fischbacher
@ 2005-03-16 13:33                         ` Yoann Padioleau
  2005-03-16 23:59                           ` Oliver Bandel
  1 sibling, 1 reply; 71+ messages in thread
From: Yoann Padioleau @ 2005-03-16 13:33 UTC (permalink / raw)
  To: Oliver Bandel; +Cc: caml-list

Oliver Bandel <oliver@first.in-berlin.de> writes:

> If he only would be cynic about "well I tried it, but it has proven
> it's a crap language... but I give you (experienced OCaml programmers)
> the chance to show me that it isn't bad (and *I* have o learn the language)"
> then this woul be ok.

I agree.

> Maybe I'm wrong here and he's a good guy. But IMHO it seems he's looking
> for proved Ocaml-failure (and not for "well, I tried it, it seems OCaml sucks,
> but please tell me it does not!", which I could accept).

I think his intention were good (but he is surely a bad guy too).

> Do you think *I'm the bad guy*?!

no :) of course not :)

> > I am not sure that making the function tail-recursive would have been the big
> > hit in this example.
> 
> But as long as nobody tried it / analzed it, your assumption is
> only an assumption, as my assumption is only an assumotion too!

Well at least my assumption about "use Map instead of assoc list is a big hit" 
has been proven. The running time from the program go from "more than 16 minutes" to just
50 seconds (this is what I call a big hit).
It would be interesting to make his function tail-rec (and keeping the assoc list)
and see if it is a big hit but I am too lazy for this and I hate 
those tail-rec transformation and I think it would
not be a big hit cos using Map and Array is the big hit.
It's your turn oliver bandel to do the job :)


> > I often transform my functions to make them tail-recursive because of stack overflow pb, not
> > that much because of speed pbs
> > (and many functions in the standard library are not tail-recursive, such as map)
> 
> 
> Well, maybe I have overestimated the tailrec-point,
> but as long as there is not a proven counter-example,
> the opposite of what I stated seems to be only an assumption too.

True.

> 
> !!! To see different results it would be nice to have different implementations
> !!! to compare them all!

I agree.

> Would be interesting to have different variations of the
> code, using different ways of coding some special tasks
> in different ways.... and maybe oe implementation,
> that uses *all* suggestions.
> 
> To do it in the language shootout, as on Jon stated it, seems
> to be a veryg good idea.

I agree.
I must confess that I have very few intuition about what is more important
in optimization, but perhaps because it depends on the program.
Sometimes X is a better optimization than Y on this program Z.
Sometimes Y is a better optimization than X on this program Z2.

> > This tail-recursion stuff is one of the thing I hate the most with fp because it forces
> > you to change your code to adapt to the machine whereas it should be the 
> > inverse.
> 
> But only because you hate it does not mean that changing the code will not result
> in better performance.

true :)


-- 
Yoann  Padioleau,  INSA de Rennes, France   www.irisa.fr/prive/padiolea/
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**____   Get Free. Be Smart.  Simply use Linux and Free Software.   ____**


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 13:10                       ` Yoann Padioleau
@ 2005-03-16 13:41                         ` Jacques Garrigue
  2005-03-16 14:14                           ` Yoann Padioleau
                                             ` (2 more replies)
  0 siblings, 3 replies; 71+ messages in thread
From: Jacques Garrigue @ 2005-03-16 13:41 UTC (permalink / raw)
  To: padiolea; +Cc: caml-list

From: Yoann Padioleau <padiolea@irisa.fr>
> Jon Harrop <jon@ffconsultancy.com> writes:
> > Although Map is asymptotically faster than List.assoc for lookup (O(ln n) vs 
> > O(n)), OCaml's Hashtbl and array-based equivalents are typically several 
> > times faster than Map.
> 
> I agree, I beleived that too but 
> I switched from Map to Hashtbl in the "troll" code and Hashtbl sux. 
> I don't know why.

Because the default hash function doesn't work well on complex
data-structures, where it has lots of collisions, and results in
putting lots of values in the same bucket. It's a bad idea to directly
use complex data structures as key anyway, but particularly bad with
hash tables.

> > In OCaml, non-tail-recursive functions are often faster than their tail 
> > recursive equivalents for small inputs (e.g. short lists). 
> 
> really ? why ?

Because tail-recursive versions do some extra work to ensure
tail-recursiveness. For instance building a list in reverse order, and
converting it back with List.rev at the end. This only pays off for
huge lists.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 13:41                         ` Jacques Garrigue
@ 2005-03-16 14:14                           ` Yoann Padioleau
  2005-03-17  0:27                             ` Oliver Bandel
  2005-03-16 17:43                           ` brogoff
  2005-03-17  0:14                           ` Oliver Bandel
  2 siblings, 1 reply; 71+ messages in thread
From: Yoann Padioleau @ 2005-03-16 14:14 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: padiolea, caml-list

Jacques Garrigue <garrigue@math.nagoya-u.ac.jp> writes:

> From: Yoann Padioleau <padiolea@irisa.fr>
> > Jon Harrop <jon@ffconsultancy.com> writes:
> > > Although Map is asymptotically faster than List.assoc for lookup (O(ln n) vs 
> > > O(n)), OCaml's Hashtbl and array-based equivalents are typically several 
> > > times faster than Map.
> > 
> > I agree, I beleived that too but 
> > I switched from Map to Hashtbl in the "troll" code and Hashtbl sux. 
> > I don't know why.
> 
> Because the default hash function doesn't work well on complex
> data-structures, where it has lots of collisions, and results in
> putting lots of values in the same bucket. It's a bad idea to directly
> use complex data structures as key anyway, but particularly bad with
> hash tables.
> 
> > > In OCaml, non-tail-recursive functions are often faster than their tail 
> > > recursive equivalents for small inputs (e.g. short lists). 
> > 
> > really ? why ?
> 
> Because tail-recursive versions do some extra work to ensure
> tail-recursiveness. For instance building a list in reverse order, and
> converting it back with List.rev at the end. This only pays off for
> huge lists.

I am happy. I have learned (or re-learned) a few stuff from this thread
so in a way from this "troll"  :)
Perhaps it is not always a waste of time to post in the news :)

It would be cool if some of those insights on optimization would be put
somewhere via a wiki.
http://haskell.org/hawiki/ThingsToAvoid  is a good stard  but it is for haskell
(but many stuff said still apply to ocaml).
I am sure that I am not the only one to ask for a wiki
(and not the only one to do nothing about it :)  )

It seems that this page is no more accessible from the new website
 http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#efficacite

> 
> Jacques Garrigue
> 

-- 
Yoann  Padioleau,  INSA de Rennes, France   www.irisa.fr/prive/padiolea/
Opinions expressed here are only mine. Je n'écris qu'à titre personnel.
**____   Get Free. Be Smart.  Simply use Linux and Free Software.   ____**


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 13:41                         ` Jacques Garrigue
  2005-03-16 14:14                           ` Yoann Padioleau
@ 2005-03-16 17:43                           ` brogoff
  2005-03-16 19:51                             ` Jon Harrop
                                               ` (3 more replies)
  2005-03-17  0:14                           ` Oliver Bandel
  2 siblings, 4 replies; 71+ messages in thread
From: brogoff @ 2005-03-16 17:43 UTC (permalink / raw)
  To: caml-list

On Wed, 16 Mar 2005, Jacques Garrigue wrote:
> From: Yoann Padioleau <padiolea@irisa.fr>
> > Jon Harrop <jon@ffconsultancy.com> writes:
> > > In OCaml, non-tail-recursive functions are often faster than their tail
> > > recursive equivalents for small inputs (e.g. short lists).
> >
> > really ? why ?
>
> Because tail-recursive versions do some extra work to ensure
> tail-recursiveness. For instance building a list in reverse order, and
> converting it back with List.rev at the end. This only pays off for
> huge lists.

No doubt the implementors will want me guillotined for bringing this up again,
but using the (still functional!) set_cdr! tail recursive functions, which do
*not* reverse the list, are always faster than the non tail recursive
list functions, even for small lists, at least in my experience. So I suspect
that your "for instance" is in fact the only reason for the disparity. I'd
welcome a counterexample.

Those Obj based List functions are what ExtLib provides, I think, and there are
even ways to get this optimization neatly into ML style languages. Maybe in ML
20XY this will be addressed.

-- Brian



^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 17:43                           ` brogoff
@ 2005-03-16 19:51                             ` Jon Harrop
  2005-03-17  3:35                               ` brogoff
  2005-03-17 11:31                               ` tail-recursion vs. no tail-recursion in list functions sebastian.egner
  2005-03-17  0:21                             ` [Caml-list] OCaml troll on Slashdot Oliver Bandel
                                               ` (2 subsequent siblings)
  3 siblings, 2 replies; 71+ messages in thread
From: Jon Harrop @ 2005-03-16 19:51 UTC (permalink / raw)
  To: caml-list

On Wednesday 16 March 2005 17:43, brogoff wrote:
> On Wed, 16 Mar 2005, Jacques Garrigue wrote:
> > Because tail-recursive versions do some extra work to ensure
> > tail-recursiveness. For instance building a list in reverse order, and
> > converting it back with List.rev at the end. This only pays off for
> > huge lists.
>
> No doubt the implementors will want me guillotined for bringing this up
> again, but using the (still functional!) set_cdr! tail recursive functions,
> which do *not* reverse the list, are always faster than the non tail
> recursive list functions, even for small lists, at least in my experience.
> So I suspect that your "for instance" is in fact the only reason for the
> disparity. I'd welcome a counterexample.

Here is one of the counterexamples given in my book, two implementations of a 
fold_right function over an implicit semi-inclusive range of integers [l..u):

# let rec fold_right1 f accu l u =
    if l < u then f (fold_right1 f accu (l + 1) u) l else accu;;
val fold_right1 : ('a -> int -> 'a) -> 'a -> int -> int -> 'a = <fun>
# let rec fold_right2 f accu l u =
    if l < u then let u = u - 1 in fold_right2 f (f accu u) l u else accu;;
val fold_right2 : ('a -> int -> 'a) -> 'a -> int -> int -> unit = <fun>

(A program for timing is at the end of this e-mail).

Here, the non-tail-recursive fold_left function is significantly faster on 
smaller lists and the tail-recursive fold_right functions is much faster in 
larger lists.

I believe there are many other counterexamples. Indeed, I would even say that 
most functions are counterexamples. Perhaps the reason is that non-tail 
recursion is used when it is natural for a given task, and transforming into 
tail-recursive form is then necessarily more complicating the function.

> Those Obj based List functions are what ExtLib provides, I think, and there
> are even ways to get this optimization neatly into ML style languages.
> Maybe in ML 20XY this will be addressed.

I don't know what the performance of such transformed code would be. Perhaps 
the transformation would slow code down. Consequently, it may be early days 
to call it an "optimisation".

Here's the timing program:

let rec fold_right1 f accu l u =
  if l < u then f (fold_right1 f accu (l + 1) u) l else accu
let rec fold_right2 f accu l u =
  if l < u then let u = u - 1 in fold_right2 f (f accu u) l u else accu

let rec test f n = if n>0 then (f (); test f (n-1))

let _ =
  let t = Unix.gettimeofday () in
  test (fun () -> ignore (fold_right1 ( + ) 0 1 5000)) 10000;
  Printf.printf "Non-tail-recursive took: %fs\n"
    (Unix.gettimeofday () -. t);
  let t = Unix.gettimeofday () in
  test (fun () -> ignore (fold_right2 ( + ) 0 1 5000)) 10000;
  Printf.printf "Tail-recursive took: %fs\n\n"
    (Unix.gettimeofday () -. t);
  let t = Unix.gettimeofday () in
  test (fun () -> ignore (fold_right1 ( + ) 0 1 50000)) 1000;
  Printf.printf "Non-tail-recursive took: %fs\n"
    (Unix.gettimeofday () -. t);
  let t = Unix.gettimeofday () in
  test (fun () -> ignore (fold_right2 ( + ) 0 1 50000)) 1000;
  Printf.printf "Tail-recursive took: %fs\n"
    (Unix.gettimeofday () -. t)

$ ./test
Non-tail-recursive took: 0.513307s
Tail-recursive took: 0.582472s

Non-tail-recursive took: 1.950229s
Tail-recursive took: 0.590756s

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 11:23                         ` Thomas Fischbacher
@ 2005-03-16 23:41                           ` Oliver Bandel
  0 siblings, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-16 23:41 UTC (permalink / raw)
  To: caml-list

On Wed, Mar 16, 2005 at 12:23:02PM +0100, Thomas Fischbacher wrote:
> 
> On Wed, 16 Mar 2005, Oliver Bandel wrote:
> 
> > > Second, many people I know still put ";;" cos they were taught that way
> > 
> > Hey, that was the way I started too! :)
> 
> I should say, I do it *on purpose*, even knowing that it is not necessary.
> 
> Why? Putting ";;" or not does not make a difference for the programmer, 
> but not using certain "syntax quirks" makes it easier to operate on the 
> source code with tools, quite in general.

Oh, good idea.

But it makes a difference, when using the toplevel, because it
immediately answers the type it infers, which is a nice feature.

Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 13:33                         ` Yoann Padioleau
@ 2005-03-16 23:59                           ` Oliver Bandel
  0 siblings, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-16 23:59 UTC (permalink / raw)
  To: caml-list

On Wed, Mar 16, 2005 at 02:33:10PM +0100, Yoann Padioleau wrote:
> Oliver Bandel <oliver@first.in-berlin.de> writes:
> 
> > If he only would be cynic about "well I tried it, but it has proven
> > it's a crap language... but I give you (experienced OCaml programmers)
> > the chance to show me that it isn't bad (and *I* have o learn the language)"
> > then this woul be ok.
> 
> I agree.
> 
> > Maybe I'm wrong here and he's a good guy. But IMHO it seems he's looking
> > for proved Ocaml-failure (and not for "well, I tried it, it seems OCaml sucks,
> > but please tell me it does not!", which I could accept).
> 
> I think his intention were good (but he is surely a bad guy too).
> 
> > Do you think *I'm the bad guy*?!
> 
> no :) of course not :)
> 
> > > I am not sure that making the function tail-recursive would have been the big
> > > hit in this example.
> > 
> > But as long as nobody tried it / analzed it, your assumption is
> > only an assumption, as my assumption is only an assumotion too!
> 
> Well at least my assumption about "use Map instead of assoc list is a big hit" 
> has been proven. The running time from the program go from "more than 16 minutes" to just
> 50 seconds (this is what I call a big hit).
> It would be interesting to make his function tail-rec (and keeping the assoc list)
> and see if it is a big hit but I am too lazy for this and I hate 
> those tail-rec transformation and I think it would
> not be a big hit cos using Map and Array is the big hit.
> It's your turn oliver bandel to do the job :)

Well, I'm too lazy for that job too. :)

But going from > 16 minutes to about 50 seconds is a good
performance boost. :)

But if c++ is beyond 1 second, that is the direction to go...


Well, I'm shure that it is not really a problem to write OCaml-code
that can compete with the C++ code. :)

But especially THAT is the reason, why there is not really
a motivation to do that job: We not have to save the church
of OCaml in a sense of a faith...

...in the sense of
    "Faith occurs when a person believes that something is true
     even though he suspects it is false".


...so it's not necessary to do the holy war...

... if you every day see, how fast OCaml programs can be...
...and if you know how much the programmer's blindness
yields to slow programs (as I often had to experience),
then no stress is coming up to do that job...

... the map-stuff has shown how far one can go with Ocaml
and I'm shure there is a lot more optimization possible.

So, there is not enough motivation to do that optimization,
because I know that it is possible. ;-)

It's up to the troll to show that tailrec functions
will *not* gain to a speedup and that 50 seconds
is the best what is possible with OCaml... ;-)

The 16 min => 50 seconds speedup has shown enough potential
and disarmed the troll I think.

The rest can be done on the language shootout, as Jon suggested.

Maybe *then* there is a motivation (maybe something like
a micro-programming contest... ;-))

Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 13:41                         ` Jacques Garrigue
  2005-03-16 14:14                           ` Yoann Padioleau
  2005-03-16 17:43                           ` brogoff
@ 2005-03-17  0:14                           ` Oliver Bandel
  2 siblings, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-17  0:14 UTC (permalink / raw)
  To: caml-list

On Wed, Mar 16, 2005 at 10:41:08PM +0900, Jacques Garrigue wrote:
> From: Yoann Padioleau <padiolea@irisa.fr>
> > Jon Harrop <jon@ffconsultancy.com> writes:
> > > Although Map is asymptotically faster than List.assoc for lookup (O(ln n) vs 
> > > O(n)), OCaml's Hashtbl and array-based equivalents are typically several 
> > > times faster than Map.
> > 
> > I agree, I beleived that too but 
> > I switched from Map to Hashtbl in the "troll" code and Hashtbl sux. 
> > I don't know why.
> 
> Because the default hash function doesn't work well on complex
> data-structures, where it has lots of collisions, and results in
> putting lots of values in the same bucket. It's a bad idea to directly
> use complex data structures as key anyway, but particularly bad with
> hash tables.


Can you please provide more details here?!
When to use Hashtbl and when not?

Are there (freely available) papers on this theme/topic?

> 
> > > In OCaml, non-tail-recursive functions are often faster than their tail 
> > > recursive equivalents for small inputs (e.g. short lists). 
> > 
> > really ? why ?
> 
> Because tail-recursive versions do some extra work to ensure
> tail-recursiveness. For instance building a list in reverse order, and
> converting it back with List.rev at the end. This only pays off for
> huge lists.

Where/when is the break-even point?

When to decide for the one or the other solution?

Trying?

Or counting the number cycles the resulting machine code will
need to do it in the one or the other way?

Or are there abstract ways of finding the break even point?

Or experience based rules of thumb?


Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 17:43                           ` brogoff
  2005-03-16 19:51                             ` Jon Harrop
@ 2005-03-17  0:21                             ` Oliver Bandel
  2005-03-17  1:05                             ` Jacques Garrigue
  2005-03-17 17:32                             ` Jason Hickey
  3 siblings, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-17  0:21 UTC (permalink / raw)
  To: caml-list

On Wed, Mar 16, 2005 at 09:43:42AM -0800, brogoff wrote:
> On Wed, 16 Mar 2005, Jacques Garrigue wrote:
> > From: Yoann Padioleau <padiolea@irisa.fr>
> > > Jon Harrop <jon@ffconsultancy.com> writes:
> > > > In OCaml, non-tail-recursive functions are often faster than their tail
> > > > recursive equivalents for small inputs (e.g. short lists).
> > >
> > > really ? why ?
> >
> > Because tail-recursive versions do some extra work to ensure
> > tail-recursiveness. For instance building a list in reverse order, and
> > converting it back with List.rev at the end. This only pays off for
> > huge lists.
> 
> No doubt the implementors will want me guillotined for bringing this up again,
> but using the (still functional!) set_cdr! tail recursive functions, which do
> *not* reverse the list, are always faster than the non tail recursive
> list functions, even for small lists, at least in my experience.

And I experienced, that adding a "_rev" at the end of a function
often makes more sense than adding a List.rev inside.

Often some code produces a list and gives it to a function that
again creates a list, based on that data.
Then "_rev"^2 means _orig and all is going well.

If there are an odd number of "_rev"-functions,
a List.rev can be added *THEN* (instead of always feel
the necessity to provide "_orig"-functions instead of
"_rev"-functions.



Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 14:14                           ` Yoann Padioleau
@ 2005-03-17  0:27                             ` Oliver Bandel
  0 siblings, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-17  0:27 UTC (permalink / raw)
  To: caml-list

On Wed, Mar 16, 2005 at 03:14:11PM +0100, Yoann Padioleau wrote:
[...]
> I am happy. I have learned (or re-learned) a few stuff from this thread
> so in a way from this "troll"  :)
> Perhaps it is not always a waste of time to post in the news :)


   "Who knows if it's good or bad?!"


> 
> It would be cool if some of those insights on optimization would be put
> somewhere via a wiki.
> http://haskell.org/hawiki/ThingsToAvoid  is a good stard  but it is for haskell
> (but many stuff said still apply to ocaml).
[...]

String.copy ?
Functional Objects?


Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 17:43                           ` brogoff
  2005-03-16 19:51                             ` Jon Harrop
  2005-03-17  0:21                             ` [Caml-list] OCaml troll on Slashdot Oliver Bandel
@ 2005-03-17  1:05                             ` Jacques Garrigue
  2005-03-17 17:32                             ` Jason Hickey
  3 siblings, 0 replies; 71+ messages in thread
From: Jacques Garrigue @ 2005-03-17  1:05 UTC (permalink / raw)
  To: brogoff; +Cc: caml-list

From: brogoff <brogoff@speakeasy.net>
> On Wed, 16 Mar 2005, Jacques Garrigue wrote:
> > From: Yoann Padioleau <padiolea@irisa.fr>
> > > Jon Harrop <jon@ffconsultancy.com> writes:
> > > > In OCaml, non-tail-recursive functions are often faster than their tail
> > > > recursive equivalents for small inputs (e.g. short lists).
> > >
> > > really ? why ?
> >
> > Because tail-recursive versions do some extra work to ensure
> > tail-recursiveness. For instance building a list in reverse order, and
> > converting it back with List.rev at the end. This only pays off for
> > huge lists.
> 
> No doubt the implementors will want me guillotined for bringing this
> up again, but using the (still functional!) set_cdr! tail recursive
> functions, which do *not* reverse the list, are always faster than
> the non tail recursive list functions, even for small lists, at
> least in my experience. So I suspect that your "for instance" is in
> fact the only reason for the disparity. I'd welcome a
> counterexample.
>
> Those Obj based List functions are what ExtLib provides, I think,
> and there are even ways to get this optimization neatly into ML
> style languages. Maybe in ML 20XY this will be addressed.

I beg to differ on performance. 
Here are the results of a micro-benchmark comparing List.map and
ExtLib.List.map.

With List.map
l10*10000: 0.117188s
l100*1000: 0.132812s
l1000*100: 0.195312s
l10000*10: 0.859375s
l100000*1: 3.328125s

With ExtLib.List.map
l10'*10000: 0.187500s
l100'*1000: 0.203125s
l1000'*100: 0.304688s
l10000'*10: 1.382812s
l100000'*1: 1.937500s

So you can see that the tail-recursive version only gets faster
somewhere between 10000 and 100000 elements. Hardly typical use of
lists. On the other hand, there are cases where the non tail-recursive
version will blow-up your stack, so you have no choice but to go with
the possibly slower tail-recursive one.

Jacques Garrigue

Code used:

let rec genlist n = if n > 0 then n :: genlist (n-1) else []

let l10 = genlist 10
let l100 = genlist 100
let l1000 = genlist 1000
let l10000 = genlist 10000
let l100000 = genlist 100000

let time f n =
  let t0 = (Unix.times ()).Unix.tms_utime in
  f n;
  (Unix.times()).Unix.tms_utime -. t0

let call_map l n =
  for i = 1 to n do ignore (List.map succ l) done

let call_extmap l n =
  for i = 1 to n do ignore (ExtList.List.map succ l) done

let process l =
  List.iter
    (fun (name, f, n) ->
      Gc.full_major ();
      let t = time f (n*100) in
      Printf.printf "%s*%d: %fs\n" name n t;
      flush stdout)
    l

let () =
  process
    [ "l10", call_map l10, 10000;
      "l100", call_map l100, 1000;
      "l1000", call_map l1000, 100;
      "l10000", call_map l10000, 10;
      "l100000", call_map l100000, 1;
      "l10'", call_extmap l10, 10000;
      "l100'", call_extmap l100, 1000;
      "l1000'", call_extmap l1000, 100;
      "l10000'", call_extmap l10000, 10;
      "l100000'", call_extmap l100000, 1; ]
  


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 19:51                             ` Jon Harrop
@ 2005-03-17  3:35                               ` brogoff
  2005-03-17  3:48                                 ` Yaron Minsky
                                                   ` (2 more replies)
  2005-03-17 11:31                               ` tail-recursion vs. no tail-recursion in list functions sebastian.egner
  1 sibling, 3 replies; 71+ messages in thread
From: brogoff @ 2005-03-17  3:35 UTC (permalink / raw)
  To: caml-list

I just ran your counterexample and the tail recursive code was faster
for each. I used native code compilation.

Byte code compilation gives similar results to yours, except that as I ran the
test on "ye olde SPARC machine", it took a hell of a lot longer.

I'll try on a few different architectures later.

Anyways, long lists do occur, and Stack_overflow at the customer site sucketh
bigtime.

-- Brian

On Wed, 16 Mar 2005, Jon Harrop wrote:

> On Wednesday 16 March 2005 17:43, brogoff wrote:
> > On Wed, 16 Mar 2005, Jacques Garrigue wrote:
> > > Because tail-recursive versions do some extra work to ensure
> > > tail-recursiveness. For instance building a list in reverse order, and
> > > converting it back with List.rev at the end. This only pays off for
> > > huge lists.
> >
> > No doubt the implementors will want me guillotined for bringing this up
> > again, but using the (still functional!) set_cdr! tail recursive functions,
> > which do *not* reverse the list, are always faster than the non tail
> > recursive list functions, even for small lists, at least in my experience.
> > So I suspect that your "for instance" is in fact the only reason for the
> > disparity. I'd welcome a counterexample.
>
> Here is one of the counterexamples given in my book, two implementations of a
> fold_right function over an implicit semi-inclusive range of integers [l..u):
>
> # let rec fold_right1 f accu l u =
>     if l < u then f (fold_right1 f accu (l + 1) u) l else accu;;
> val fold_right1 : ('a -> int -> 'a) -> 'a -> int -> int -> 'a = <fun>
> # let rec fold_right2 f accu l u =
>     if l < u then let u = u - 1 in fold_right2 f (f accu u) l u else accu;;
> val fold_right2 : ('a -> int -> 'a) -> 'a -> int -> int -> unit = <fun>
>
> (A program for timing is at the end of this e-mail).
>
> Here, the non-tail-recursive fold_left function is significantly faster on
> smaller lists and the tail-recursive fold_right functions is much faster in
> larger lists.
>
> I believe there are many other counterexamples. Indeed, I would even say that
> most functions are counterexamples. Perhaps the reason is that non-tail
> recursion is used when it is natural for a given task, and transforming into
> tail-recursive form is then necessarily more complicating the function.
>
> > Those Obj based List functions are what ExtLib provides, I think, and there
> > are even ways to get this optimization neatly into ML style languages.
> > Maybe in ML 20XY this will be addressed.
>
> I don't know what the performance of such transformed code would be. Perhaps
> the transformation would slow code down. Consequently, it may be early days
> to call it an "optimisation".
>
> Here's the timing program:
>
> let rec fold_right1 f accu l u =
>   if l < u then f (fold_right1 f accu (l + 1) u) l else accu
> let rec fold_right2 f accu l u =
>   if l < u then let u = u - 1 in fold_right2 f (f accu u) l u else accu
>
> let rec test f n = if n>0 then (f (); test f (n-1))
>
> let _ =
>   let t = Unix.gettimeofday () in
>   test (fun () -> ignore (fold_right1 ( + ) 0 1 5000)) 10000;
>   Printf.printf "Non-tail-recursive took: %fs\n"
>     (Unix.gettimeofday () -. t);
>   let t = Unix.gettimeofday () in
>   test (fun () -> ignore (fold_right2 ( + ) 0 1 5000)) 10000;
>   Printf.printf "Tail-recursive took: %fs\n\n"
>     (Unix.gettimeofday () -. t);
>   let t = Unix.gettimeofday () in
>   test (fun () -> ignore (fold_right1 ( + ) 0 1 50000)) 1000;
>   Printf.printf "Non-tail-recursive took: %fs\n"
>     (Unix.gettimeofday () -. t);
>   let t = Unix.gettimeofday () in
>   test (fun () -> ignore (fold_right2 ( + ) 0 1 50000)) 1000;
>   Printf.printf "Tail-recursive took: %fs\n"
>     (Unix.gettimeofday () -. t)
>
> $ ./test
> Non-tail-recursive took: 0.513307s
> Tail-recursive took: 0.582472s
>
> Non-tail-recursive took: 1.950229s
> Tail-recursive took: 0.590756s
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.
> Objective CAML for Scientists
> http://www.ffconsultancy.com/products/ocaml_for_scientists
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17  3:35                               ` brogoff
@ 2005-03-17  3:48                                 ` Yaron Minsky
  2005-03-17 10:16                                   ` Jon Harrop
  2005-03-17  9:45                                 ` Christian Szegedy
  2005-03-17 10:31                                 ` Jon Harrop
  2 siblings, 1 reply; 71+ messages in thread
From: Yaron Minsky @ 2005-03-17  3:48 UTC (permalink / raw)
  To: brogoff; +Cc: caml-list

On Wed, 16 Mar 2005 19:35:17 -0800 (PST), brogoff
<brogoff@speakeasy.net> wrote:
> Anyways, long lists do occur, and Stack_overflow at the customer site sucketh
> bigtime.

I completely agree.  As someone who makes extensive use of OCaml in a
business setting, the fact that the standard libraries throw
exceptions on large data structures is a real pain.  It's a violation
of the principle of least surprise, and I've run into it in practice
quite a few times.  Our solution was to just rewrite the list module
with tail-recursive versions.  We're happy to make the performance
tradeoff.  If we really want things to be fast, List.map is no good
anyway, due to the lack of inlining of the function parameter.

I do think that it would be a great thing if the tail-recursive list
functions were moved into the standard library.

Yaron


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17  3:35                               ` brogoff
  2005-03-17  3:48                                 ` Yaron Minsky
@ 2005-03-17  9:45                                 ` Christian Szegedy
  2005-03-17 10:31                                 ` Jon Harrop
  2 siblings, 0 replies; 71+ messages in thread
From: Christian Szegedy @ 2005-03-17  9:45 UTC (permalink / raw)
  To: caml-list

brogoff wrote:

>I just ran your counterexample and the tail recursive code was faster
>for each. I used native code compilation.
>
>Byte code compilation gives similar results to yours, except that as I ran the
>test on "ye olde SPARC machine", it took a hell of a lot longer.
>  
>
As far as I know, the bytecode compiler does not eliminate
tail calls.


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17  3:48                                 ` Yaron Minsky
@ 2005-03-17 10:16                                   ` Jon Harrop
  2005-03-17 10:47                                     ` Oliver Bandel
  2005-03-17 18:06                                     ` brogoff
  0 siblings, 2 replies; 71+ messages in thread
From: Jon Harrop @ 2005-03-17 10:16 UTC (permalink / raw)
  To: caml-list

On Thursday 17 March 2005 03:48, Yaron Minsky wrote:
> On Wed, 16 Mar 2005 19:35:17 -0800 (PST), brogoff
> <brogoff@speakeasy.net> wrote:
> > Anyways, long lists do occur, and Stack_overflow at the customer site
> > sucketh bigtime.
>
> I completely agree.  As someone who makes extensive use of OCaml in a
> business setting, the fact that the standard libraries throw
> exceptions on large data structures is a real pain.

I believe the Stack_overflow exception is not necessarily thrown - the process 
may simply die. IIRC, I found this on x86 Debian Linux when swap was turned 
off.

> It's a violation 
> of the principle of least surprise, and I've run into it in practice
> quite a few times.

I understand your (and Brian's) concern but I think the solution is to be more 
careful when programming, rather than to replace all of the library 
functions. That seems like a sledgehammer to crack a nut to me...

> Our solution was to just rewrite the list module 
> with tail-recursive versions.

I would recommend using and making documentation instead, as 
non-tail-recursive functions can be very useful. In non-trivial code I would 
recommend putting the asymptotic complexity of stack use in the docs.

> We're happy to make the performance 
> tradeoff.  If we really want things to be fast, List.map is no good
> anyway, due to the lack of inlining of the function parameter.

Yes, if your program uses non-tail-recursive functions with very deep 
recursion then it will be much slower anyway. Consequently, you are likely to 
fix this whilst optimising anyway.

As Brian has said before, users can throw you a sideball by giving input which 
requires deep recursion by a non-tail-recursive function which had not been 
expected by the programmer. Provided you are thorough, this shouldn't happen 
though.

I must say that I've had fewer stack problems with my OCaml code than with 
code I've used in other languages...

> I do think that it would be a great thing if the tail-recursive list
> functions were moved into the standard library.

I would not like to see trivial tail-recursive alternatives put into the 
library (e.g. let map f l = rev_map f (rev l)). I think it would bloat the 
library unnecessarily and they are often not the best solution, particularly 
in combination. For example, writing these functions yourself makes a rev rev 
and the following deforestation obvious. Given that these are likely to be 
performance-critical functions, this is obviously useful.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17  3:35                               ` brogoff
  2005-03-17  3:48                                 ` Yaron Minsky
  2005-03-17  9:45                                 ` Christian Szegedy
@ 2005-03-17 10:31                                 ` Jon Harrop
  2005-03-17 11:11                                   ` Ville-Pertti Keinonen
  2 siblings, 1 reply; 71+ messages in thread
From: Jon Harrop @ 2005-03-17 10:31 UTC (permalink / raw)
  To: caml-list

On Thursday 17 March 2005 03:35, brogoff wrote:
> I just ran your counterexample and the tail recursive code was faster
> for each. I used native code compilation.

That's odd. My previous results were for a 1.2GHz Athlon t-bird, ocamlopt 
3.08. Tail recursion is also significantly slower on an 866MHz P3 (x86 
native-code) with ocamlopt 3.07:

Non-tail-recursive took: 0.873906s
Tail-recursive took: 1.005320s

Non-tail-recursive took: 4.288313s
Tail-recursive took: 0.986330s

And on an Athlon MP 2600+ with ocamlopt 3.06:

Non-tail-recursive took: 0.289890s
Tail-recursive took: 0.332338s

Non-tail-recursive took: 1.981812s
Tail-recursive took: 0.332071s

This may be a cache effect as these CPUs all have 256kb cache. Perhaps if you 
try a smaller/larger problem depending on your cache size...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17 10:16                                   ` Jon Harrop
@ 2005-03-17 10:47                                     ` Oliver Bandel
  2005-03-17 18:06                                     ` brogoff
  1 sibling, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-17 10:47 UTC (permalink / raw)
  To: caml-list

On Thu, Mar 17, 2005 at 10:16:17AM +0000, Jon Harrop wrote:
> On Thursday 17 March 2005 03:48, Yaron Minsky wrote:
> > On Wed, 16 Mar 2005 19:35:17 -0800 (PST), brogoff
> > <brogoff@speakeasy.net> wrote:
> > > Anyways, long lists do occur, and Stack_overflow at the customer site
> > > sucketh bigtime.
> >
> > I completely agree.  As someone who makes extensive use of OCaml in a
> > business setting, the fact that the standard libraries throw
> > exceptions on large data structures is a real pain.
> 
> I believe the Stack_overflow exception is not necessarily thrown - the process 
> may simply die. IIRC, I found this on x86 Debian Linux when swap was turned 
> off.

Then it is the OS what kills your process, not OCaml.
If your process grows too much, the OS can/must
kill it, so that other processes has enough room to live.

If you have swap-space, the OS can use it.
If not, there is no other possibility than killing the
prcoess.

So, use swpa space, or buy some more memeory for your computer.

It's not hype to have swap-space because people often say
"I have enough memory in RAM - I don't need a awap."
But as you see this is a misleading assumption.

If swap-space would be of no use, I'm shure the Linux-/Debian
developers/maintainers had thrown it out of the kernel.

When the OS kills your process, then OCaml has no chance to
stop this...

Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17 10:31                                 ` Jon Harrop
@ 2005-03-17 11:11                                   ` Ville-Pertti Keinonen
  0 siblings, 0 replies; 71+ messages in thread
From: Ville-Pertti Keinonen @ 2005-03-17 11:11 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

On Thu, 2005-03-17 at 10:31 +0000, Jon Harrop wrote:
> On Thursday 17 March 2005 03:35, brogoff wrote:
> > I just ran your counterexample and the tail recursive code was faster
> > for each. I used native code compilation.
> 
> That's odd. My previous results were for a 1.2GHz Athlon t-bird, ocamlopt 
> 3.08. Tail recursion is also significantly slower on an 866MHz P3 (x86 

It could be specific to i386 code generation.

Tail-recursive is faster for both of your tests on both of the amd64
machines (512/1024k L2 cache sizes) I tried on when using 64-bit
binaries but slightly slower for the first case when using 32-bit
binaries.



^ permalink raw reply	[flat|nested] 71+ messages in thread

* tail-recursion vs. no tail-recursion in list functions
  2005-03-16 19:51                             ` Jon Harrop
  2005-03-17  3:35                               ` brogoff
@ 2005-03-17 11:31                               ` sebastian.egner
  2005-03-17 21:41                                 ` [Caml-list] " Oliver Bandel
  2005-03-18  1:13                                 ` Jacques Garrigue
  1 sibling, 2 replies; 71+ messages in thread
From: sebastian.egner @ 2005-03-17 11:31 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 5475 bytes --]

Just to chime in on this...

Did anybody every consider the following simple solution for the 'map' 
problem?

let unbreakable_map f xs =
    let rec 
      map limit f xs = (* recursion depth limited to limit *)
        match xs with
          []                   -> []
        | x::xs when limit > 0 -> let f_x = f x in f_x::(map (limit-1) f 
xs)
        | _                    -> List.rev_append (List.rev_map f xs) []
    in  map 512 f xs;;

The function is not tail-recursive for lists of length up to 512---at 
which point it
switches to a tail-recursive algorithm and uses the heap instead of the 
stack
to keep track of structural recursion.

The overhead introduced is counting down and comparing an int-counter.

Clearly, this solution is applicable to most other structural operations 
on lists
and it gets rid of many stack overflows nicely. 

Since the "magic number" 512 necessarily represents a trade-off, I would 
like
to see it being chosen at the time the Ocaml compiler is constructed for a 
specific
target architecture, i.e. at the time somebody more or less knows the 
stack size.

Cheers,

Sebastian.


----
Dr. Sebastian Egner
Senior Scientist Channel Coding & Modulation
Philips Research Laboratories
Prof. Holstlaan 4 (WDC 1-051, 1st floor, room 51)
5656 AA Eindhoven
The Netherlands
tel:       +31 40 27-43166   *** SINCE 10-Feb-2005 ***
fax:      +31 40 27-44004
email: sebastian.egner@philips.com









Jon Harrop <jon@ffconsultancy.com>
Sent by: 
caml-list-admin@yquem.inria.fr
16-03-2005 20:51
 
        To:     caml-list@yquem.inria.fr
        cc:     (bcc: Sebastian Egner/EHV/RESEARCH/PHILIPS)
        Subject:        Re: [Caml-list] OCaml troll on Slashdot
        Classification: 




On Wednesday 16 March 2005 17:43, brogoff wrote:
> On Wed, 16 Mar 2005, Jacques Garrigue wrote:
> > Because tail-recursive versions do some extra work to ensure
> > tail-recursiveness. For instance building a list in reverse order, and
> > converting it back with List.rev at the end. This only pays off for
> > huge lists.
>
> No doubt the implementors will want me guillotined for bringing this up
> again, but using the (still functional!) set_cdr! tail recursive 
functions,
> which do *not* reverse the list, are always faster than the non tail
> recursive list functions, even for small lists, at least in my 
experience.
> So I suspect that your "for instance" is in fact the only reason for the
> disparity. I'd welcome a counterexample.

Here is one of the counterexamples given in my book, two implementations 
of a 
fold_right function over an implicit semi-inclusive range of integers 
[l..u):

# let rec fold_right1 f accu l u =
    if l < u then f (fold_right1 f accu (l + 1) u) l else accu;;
val fold_right1 : ('a -> int -> 'a) -> 'a -> int -> int -> 'a = <fun>
# let rec fold_right2 f accu l u =
    if l < u then let u = u - 1 in fold_right2 f (f accu u) l u else 
accu;;
val fold_right2 : ('a -> int -> 'a) -> 'a -> int -> int -> unit = <fun>

(A program for timing is at the end of this e-mail).

Here, the non-tail-recursive fold_left function is significantly faster on 

smaller lists and the tail-recursive fold_right functions is much faster 
in 
larger lists.

I believe there are many other counterexamples. Indeed, I would even say 
that 
most functions are counterexamples. Perhaps the reason is that non-tail 
recursion is used when it is natural for a given task, and transforming 
into 
tail-recursive form is then necessarily more complicating the function.

> Those Obj based List functions are what ExtLib provides, I think, and 
there
> are even ways to get this optimization neatly into ML style languages.
> Maybe in ML 20XY this will be addressed.

I don't know what the performance of such transformed code would be. 
Perhaps 
the transformation would slow code down. Consequently, it may be early 
days 
to call it an "optimisation".

Here's the timing program:

let rec fold_right1 f accu l u =
  if l < u then f (fold_right1 f accu (l + 1) u) l else accu
let rec fold_right2 f accu l u =
  if l < u then let u = u - 1 in fold_right2 f (f accu u) l u else accu

let rec test f n = if n>0 then (f (); test f (n-1))

let _ =
  let t = Unix.gettimeofday () in
  test (fun () -> ignore (fold_right1 ( + ) 0 1 5000)) 10000;
  Printf.printf "Non-tail-recursive took: %fs\n"
    (Unix.gettimeofday () -. t);
  let t = Unix.gettimeofday () in
  test (fun () -> ignore (fold_right2 ( + ) 0 1 5000)) 10000;
  Printf.printf "Tail-recursive took: %fs\n\n"
    (Unix.gettimeofday () -. t);
  let t = Unix.gettimeofday () in
  test (fun () -> ignore (fold_right1 ( + ) 0 1 50000)) 1000;
  Printf.printf "Non-tail-recursive took: %fs\n"
    (Unix.gettimeofday () -. t);
  let t = Unix.gettimeofday () in
  test (fun () -> ignore (fold_right2 ( + ) 0 1 50000)) 1000;
  Printf.printf "Tail-recursive took: %fs\n"
    (Unix.gettimeofday () -. t)

$ ./test
Non-tail-recursive took: 0.513307s
Tail-recursive took: 0.582472s

Non-tail-recursive took: 1.950229s
Tail-recursive took: 0.590756s

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists

_______________________________________________
Caml-list mailing list. Subscription management:
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
Archives: http://caml.inria.fr
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs


[-- Attachment #2: Type: text/html, Size: 8054 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-16 17:43                           ` brogoff
                                               ` (2 preceding siblings ...)
  2005-03-17  1:05                             ` Jacques Garrigue
@ 2005-03-17 17:32                             ` Jason Hickey
  2005-03-17 19:06                               ` Marcin 'Qrczak' Kowalczyk
  3 siblings, 1 reply; 71+ messages in thread
From: Jason Hickey @ 2005-03-17 17:32 UTC (permalink / raw)
  To: brogoff; +Cc: caml-list

brogoff wrote:
> No doubt the implementors will want me guillotined for bringing this up again,
> but using the (still functional!) set_cdr! tail recursive functions, which do
> *not* reverse the list, are always faster than the non tail recursive
> list functions, even for small lists, at least in my experience. So I suspect
> that your "for instance" is in fact the only reason for the disparity. I'd
> welcome a counterexample.

This optimization is probably reasonable.  Note that assignment can have 
a somewhat unexpected cost when the runtime uses a generational garbage 
collector (as OCaml does).

Speaking generally, the collector would like the invariant "all pointers 
in a generation refer to younger generations", where the "younger" 
relation is reflexive.  This is true for purely functional languages, 
but not true when assignment is added.

In general, the implementation needs to add a check during assignment: 
"if the value being modified belongs to a strictly older generation than 
the value being stored, then mark it."

In the implementation of List.map using set_cdr! it should be possible 
to eliminate the check.  The cons-cell was just allocated, so it should 
belong to the minor heap.

Jason

-- 
Jason Hickey                  http://www.cs.caltech.edu/~jyh
Caltech Computer Science      Tel: 626-395-6568 FAX: 626-792-4257


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17 10:16                                   ` Jon Harrop
  2005-03-17 10:47                                     ` Oliver Bandel
@ 2005-03-17 18:06                                     ` brogoff
  2005-03-17 19:15                                       ` Marcin 'Qrczak' Kowalczyk
  2005-03-17 21:31                                       ` Oliver Bandel
  1 sibling, 2 replies; 71+ messages in thread
From: brogoff @ 2005-03-17 18:06 UTC (permalink / raw)
  To: caml-list

On Thu, 17 Mar 2005, Jon Harrop wrote:
> On Thursday 17 March 2005 03:48, Yaron Minsky wrote:
> > On Wed, 16 Mar 2005 19:35:17 -0800 (PST), brogoff
> > <brogoff@speakeasy.net> wrote:
> > > Anyways, long lists do occur, and Stack_overflow at the customer site
> > > sucketh bigtime.
> >
> > I completely agree.  As someone who makes extensive use of OCaml in a
> > business setting, the fact that the standard libraries throw
> > exceptions on large data structures is a real pain.
>
> I believe the Stack_overflow exception is not necessarily thrown - the process
> may simply die. IIRC, I found this on x86 Debian Linux when swap was turned
> off.
>
> > It's a violation
> > of the principle of least surprise, and I've run into it in practice
> > quite a few times.
>
> I understand your (and Brian's) concern but I think the solution is to be more
> careful when programming, rather than to replace all of the library
> functions. That seems like a sledgehammer to crack a nut to me...

There are a few problems with that suggestion. The cases where I've been bitten
didn't have lists of length 100_000 (or whatever the rather arbitrary number
above which we're not supposed to use lists) but rather had quite a few lists
that were close enough to that number, and the maps (appends, etc.) were being
called inside other mapping functions, on other lists.

Also, as I state above, the number is arbitrary, and having OCaml choke at some
particular size rather than letting me use large lists violates that least
surprise principle. I had an offline discussion recently with another caml-list
person in which he told me that he wished OCaml used Bignums instead of int's
by default. I disagree, but I don't think it's a dumb idea. The behavior of
the standard List functions is worse IMO. Maybe the standard Lisp.map should be
named List.unsafe_map (1/2 :-))?

I realize that this problem can be coded around, sometimes with better data
structures, or by the double reversing approach (which is what I used to use)
but my own sense of programming language aesthetics is that this is a flaw, or
at least a hole in the language that should be filled one day.

> > We're happy to make the performance
> > tradeoff.  If we really want things to be fast, List.map is no good
> > anyway, due to the lack of inlining of the function parameter.

That's quite true. However, Yaron, I bet you usually write the program with map
first, and then optimize later iff it isn't fast enough, right? Manual inlining
makes code uglier.

> Yes, if your program uses non-tail-recursive functions with very deep
> recursion then it will be much slower anyway. Consequently, you are likely to
> fix this whilst optimising anyway.
>
> As Brian has said before, users can throw you a sideball by giving input which
> requires deep recursion by a non-tail-recursive function which had not been
> expected by the programmer. Provided you are thorough, this shouldn't happen
> though.

As I said above, you can have "not so deep recursions" nested inside each other
many times, leading to a deep recursion. Besides, "deep" is arbitrary.

> I must say that I've had fewer stack problems with my OCaml code than with
> code I've used in other languages...

Absolutely correct, and my whining should in no way be construed as saying
that OCaml sucks. However, when the language is so good, it's users begin to
desire perfection. When a language is like, say C++ or Perl, then Ada and
Python look really good.

>
> > I do think that it would be a great thing if the tail-recursive list
> > functions were moved into the standard library.
>
> I would not like to see trivial tail-recursive alternatives put into the
> library (e.g. let map f l = rev_map f (rev l)).


I agree with you here, and I'm only beating this dead dromedary to keep up the
pressure for a better solution. It's known in theory how to better than
the double rev solution, but as Jacques pointed out (and I accept his
counterexample for now!) there may be implications on GC which still give a
slight edge to the non tail recursive versions for smaller lists.

-- Brian


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17 17:32                             ` Jason Hickey
@ 2005-03-17 19:06                               ` Marcin 'Qrczak' Kowalczyk
  0 siblings, 0 replies; 71+ messages in thread
From: Marcin 'Qrczak' Kowalczyk @ 2005-03-17 19:06 UTC (permalink / raw)
  To: caml-list

Jason Hickey <jyh@cs.caltech.edu> writes:

> In general, the implementation needs to add a check during assignment:
> "if the value being modified belongs to a strictly older generation
> than the value being stored, then mark it."
>
> In the implementation of List.map using set_cdr! it should be possible
> to eliminate the check.  The cons-cell was just allocated, so it
> should belong to the minor heap.

No, the next cell was allocated afterwards, and it may have triggered GC
in the meantime.

When you allocate a sufficiently large number of cons cells in ascending
order, a GC during that operation will cause some link to be old to young.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17 18:06                                     ` brogoff
@ 2005-03-17 19:15                                       ` Marcin 'Qrczak' Kowalczyk
  2005-03-18 17:46                                         ` brogoff
  2005-03-17 21:31                                       ` Oliver Bandel
  1 sibling, 1 reply; 71+ messages in thread
From: Marcin 'Qrczak' Kowalczyk @ 2005-03-17 19:15 UTC (permalink / raw)
  To: caml-list

brogoff <brogoff@speakeasy.net> writes:

> Also, as I state above, the number is arbitrary, and having OCaml
> choke at some particular size rather than letting me use large lists
> violates that least surprise principle. I had an offline discussion
> recently with another caml-list person in which he told me that he
> wished OCaml used Bignums instead of int's by default. I disagree,
> but I don't think it's a dumb idea. The behavior of the standard
> List functions is worse IMO. Maybe the standard Lisp.map should be
> named List.unsafe_map (1/2 :-))?

It's not the fault of the mapping function but of the stack being
non-extensible. A user-written recursion can blow it too. Functional
programming is supposed to encourage recursion, and a non-tail-recursive
'map' is much more readable than alternatives.

My implementation of my language Kogut has extensible stack.
And transparent bignums when appropriate. Yes, it's slower,
but correctness is more important.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17 18:06                                     ` brogoff
  2005-03-17 19:15                                       ` Marcin 'Qrczak' Kowalczyk
@ 2005-03-17 21:31                                       ` Oliver Bandel
  1 sibling, 0 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-17 21:31 UTC (permalink / raw)
  To: caml-list

On Thu, Mar 17, 2005 at 10:06:45AM -0800, brogoff wrote:
[...]
> Also, as I state above, the number is arbitrary, and having OCaml choke at some
> particular size rather than letting me use large lists violates that least
> surprise principle. I had an offline discussion recently with another caml-list
> person in which he told me that he wished OCaml used Bignums instead of int's
> by default. I disagree, but I don't think it's a dumb idea. The behavior of
> the standard List functions is worse IMO. Maybe the standard Lisp.map should be
> named List.unsafe_map (1/2 :-))?


Well, or call
ocaml ocaml_unsafe,
ocamlc ocamlc_unsafe
ocamlopt ocamlopt_unsafe
as long as they are not able to convert simple-recursive
programs into tail-recursive programs (per default or
per cli-option or at all).


> 
> I realize that this problem can be coded around, sometimes with better data
> structures, or by the double reversing approach (which is what I used to use)
> but my own sense of programming language aesthetics is that this is a flaw, or
> at least a hole in the language that should be filled one day.

M aybe one day, the cli-switch "-tailrec-all" or "-force-tailrec"
will automatically convert all functions that aren't tailrec
into tailrec ones.
Or maybe a pragma (something like in _inline_)
will be used to convert certain functions
into it's tailrec counterpart internally (maybe only
when a switch "-tailrec-by-pragma" is set).


Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] tail-recursion vs. no tail-recursion in list functions
  2005-03-17 11:31                               ` tail-recursion vs. no tail-recursion in list functions sebastian.egner
@ 2005-03-17 21:41                                 ` Oliver Bandel
  2005-03-18  0:04                                   ` David Brown
  2005-03-18  0:06                                   ` Karl Zilles
  2005-03-18  1:13                                 ` Jacques Garrigue
  1 sibling, 2 replies; 71+ messages in thread
From: Oliver Bandel @ 2005-03-17 21:41 UTC (permalink / raw)
  To: caml-list

On Thu, Mar 17, 2005 at 12:31:57PM +0100, sebastian.egner@philips.com wrote:
> Just to chime in on this...
> 
> Did anybody every consider the following simple solution for the 'map' 
> problem?
> 
> let unbreakable_map f xs =
>     let rec 
>       map limit f xs = (* recursion depth limited to limit *)
>         match xs with
>           []                   -> []
>         | x::xs when limit > 0 -> let f_x = f x in f_x::(map (limit-1) f 
> xs)
>         | _                    -> List.rev_append (List.rev_map f xs) []
>     in  map 512 f xs;;
> 
> The function is not tail-recursive for lists of length up to 512---at 
> which point it
> switches to a tail-recursive algorithm and uses the heap instead of the 
> stack
> to keep track of structural recursion.


IMHO this does not makes sense.
Better checking listlength with List.length and then calling the
needed function directly.
Why using an integer counter... this introduces overhead.

Better use the match on limit and then call one of the
functions (which both are without a limit-incrementor).

BTW: As stated out by other people, the needed limit can vary.
     so it should be possible to give it as argument (at least
     as an optional value).


Ciao,
   Oliver


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] tail-recursion vs. no tail-recursion in list functions
  2005-03-17 21:41                                 ` [Caml-list] " Oliver Bandel
@ 2005-03-18  0:04                                   ` David Brown
  2005-03-18  0:06                                   ` Karl Zilles
  1 sibling, 0 replies; 71+ messages in thread
From: David Brown @ 2005-03-18  0:04 UTC (permalink / raw)
  To: Oliver Bandel; +Cc: caml-list

On Thu, Mar 17, 2005 at 10:41:13PM +0100, Oliver Bandel wrote:

> IMHO this does not makes sense.
> Better checking listlength with List.length and then calling the
> needed function directly.
> Why using an integer counter... this introduces overhead.

List.length is O(n) and will be at least as much overhead as a counter kept
for the beginning portion of the list.

Dave


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] tail-recursion vs. no tail-recursion in list functions
  2005-03-17 21:41                                 ` [Caml-list] " Oliver Bandel
  2005-03-18  0:04                                   ` David Brown
@ 2005-03-18  0:06                                   ` Karl Zilles
  1 sibling, 0 replies; 71+ messages in thread
From: Karl Zilles @ 2005-03-18  0:06 UTC (permalink / raw)
  To: Oliver Bandel; +Cc: caml-list

Oliver Bandel wrote:
> On Thu, Mar 17, 2005 at 12:31:57PM +0100, sebastian.egner@philips.com wrote:
>>let unbreakable_map f xs =
>>    let rec 
>>      map limit f xs = (* recursion depth limited to limit *)
>>        match xs with
>>          []                   -> []
>>        | x::xs when limit > 0 -> let f_x = f x in f_x::(map (limit-1) f 
>>xs)
>>        | _                    -> List.rev_append (List.rev_map f xs) []
>>    in  map 512 f xs;;
>>
>>The function is not tail-recursive for lists of length up to 512---at 
>>which point it
>>switches to a tail-recursive algorithm and uses the heap instead of the 
>>stack
>>to keep track of structural recursion.
> 
> IMHO this does not makes sense.
> Better checking listlength with List.length and then calling the
> needed function directly.
> Why using an integer counter... this introduces overhead.

Well, if you use List.length, then you're running an integer counter 
over the entire length of the list.  His way, you only count the first 
512 items.

However, given the weird benchmark timings, God knows which would be 
faster :)


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] tail-recursion vs. no tail-recursion in list functions
  2005-03-17 11:31                               ` tail-recursion vs. no tail-recursion in list functions sebastian.egner
  2005-03-17 21:41                                 ` [Caml-list] " Oliver Bandel
@ 2005-03-18  1:13                                 ` Jacques Garrigue
  1 sibling, 0 replies; 71+ messages in thread
From: Jacques Garrigue @ 2005-03-18  1:13 UTC (permalink / raw)
  To: sebastian.egner; +Cc: caml-list

From: sebastian.egner@philips.com

> Did anybody every consider the following simple solution for the 'map' 
> problem?
> 
> let unbreakable_map f xs =
>     let rec 
>       map limit f xs = (* recursion depth limited to limit *)
>         match xs with
>           []                   -> []
>         | x::xs when limit > 0 -> let f_x = f x in f_x::(map (limit-1) f 
> xs)
>         | _                    -> List.rev_append (List.rev_map f xs) []
>     in  map 512 f xs;;
> 
> The function is not tail-recursive for lists of length up to
> 512---at which point it switches to a tail-recursive algorithm and
> uses the heap instead of the stack to keep track of structural
> recursion.

I just tried to do it, and it seems to work well. The
overhead of the counter is really small.
Note that in the long list case I call the extlib map function rather
than rev o rev_map, as it performs better on such long lists.

Results: (ocamlopt, limit=1000)
using List.map
l10*10000: 0.117188s
l100*1000: 0.132812s
l1000*100: 0.195312s
l10000*10: 0.843750s
l100000*1: 3.328125
using your approach (reverting to ExtLib.List.map)
l10'*10000: 0.140625s
l100'*1000: 0.140625s
l1000'*100: 0.203125s
l10000'*10: 1.265625s
l100000'*1: 1.945312s
using ExtLib.List.map
l10'*10000: 0.187500s
l100'*1000: 0.203125s
l1000'*100: 0.304688s
l10000'*10: 1.382812s
l100000'*1: 1.937500s

The performance is even better with append, and with bytecode also.
So this seems that at least extlib could use that.

One criticism is that it is not really tail recursive, as it consumes
some large amount of stack, albeit limited. Brian seemed to imply that he
has programs for which even this would be bad, but I'm really curious
to such case. Basically it would mean using map recursively rather
deep, meaning exponential runtime anyway, so I'm not sure this is a
problem.

> Since the "magic number" 512 necessarily represents a trade-off, I
> would like to see it being chosen at the time the Ocaml compiler is
> constructed for a specific target architecture, i.e. at the time
> somebody more or less knows the stack size.

Honestly, this part is going to be difficult.
And I'm not sure it is that relevant anyway.
A fixed value already gives safety, good performance on small lists,
and reasonable overall performance.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-17 19:15                                       ` Marcin 'Qrczak' Kowalczyk
@ 2005-03-18 17:46                                         ` brogoff
  2005-03-18 18:44                                           ` Marcin 'Qrczak' Kowalczyk
  0 siblings, 1 reply; 71+ messages in thread
From: brogoff @ 2005-03-18 17:46 UTC (permalink / raw)
  To: caml-list

On Thu, 17 Mar 2005, Marcin 'Qrczak' Kowalczyk wrote:
> It's not the fault of the mapping function but of the stack being
> non-extensible. A user-written recursion can blow it too. Functional
> programming is supposed to encourage recursion, and a non-tail-recursive
> 'map' is much more readable than alternatives.

Interesting approach. Do you have any information as to how big the performance
hit is?

I've never used SML/NJ except for a few toy programs, but I recall that it
puts activation records on the Gc'ed heap (correct me if I'm wrong
someone) so that call/cc is more efficient, so stack overflows shouldn't
be a problem there either. Could you comment on why you chose extensible stacks
rather than the SMLNJ approach for Kogut.

> My implementation of my language Kogut has extensible stack.
> And transparent bignums when appropriate. Yes, it's slower,
> but correctness is more important.

Hard to disagree when you put it that way, but there you seem to be posing
a false dichotomy. With enough work, C code can be made safe.

What I think you intend is that you'd rather it be easy to write safe code
than that it be asy to write fast code, in the language. I wouldn't mind
that, as long as it  isn't ridiculously hard or impossible to do the latter in
the language.

-- Brian


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-18 17:46                                         ` brogoff
@ 2005-03-18 18:44                                           ` Marcin 'Qrczak' Kowalczyk
  0 siblings, 0 replies; 71+ messages in thread
From: Marcin 'Qrczak' Kowalczyk @ 2005-03-18 18:44 UTC (permalink / raw)
  To: caml-list

brogoff <brogoff@speakeasy.net> writes:

>> It's not the fault of the mapping function but of the stack
>> being non-extensible. A user-written recursion can blow it too.
>> Functional programming is supposed to encourage recursion, and a
>> non-tail-recursive 'map' is much more readable than alternatives.
>
> Interesting approach. Do you have any information as to how big the
> performance hit is?

No.

I recall there was some paper which claimed that heap allocation is
significantly more expensive than stack allocation even with the most
clever GCs. I couldn't find it now. My stack frame allocation is very
similar to heap allocation.

What matters is not only the overhead of stack overflow checking
itself, but the combined effect of several interdependent design
choices. Even if I measured the cost of stack overflow checking in
isolation, it would not give a meaningful answer because it requires
and provides other things and thus the cost would be different if
applied to an implementation with different properties.

I implement a custom stack instead of using the system stack. Effects:
- a C global variable is used for the stack pointer instead of a
  machine register, thus stack frame allocation and access to stack
  contents is slower (even if it was not checked for overflow)
- checking for stack overflow adds overhead
+ tail call optimization is easier
+ scanning the stack by the GC is easier
+ portable green threads are easier
+ stack overflow is not fatal
+ triggering a context switch is done by faking the stack overflow
  condition, so it doesn't need an *additional* overhead (except that
  the stack limit is a volatile variable and allocation of a stack
  frame is one machine instruction longer because of that)

> I've never used SML/NJ except for a few toy programs, but I recall
> that it puts activation records on the Gc'ed heap (correct me if I'm
> wrong someone) so that call/cc is more efficient, so stack overflows
> shouldn't be a problem there either. Could you comment on why you
> chose extensible stacks rather than the SMLNJ approach for Kogut.

It should be slightly more efficient because allocating stack frames
doesn't increase the frequency of GCs, because stack frames don't need
to be copied by a copying GC, and because they don't need a link to
the previous frame (they do have a "descriptor" pointer though, which
stores their size and is also used to generate stack trace on uncaught
exceptions).

I haven't measured how large the efficiency difference is. It could
even be negative, because I must deallocate a stack frame explicitly,
but I doubt that.

> What I think you intend is that you'd rather it be easy to write
> safe code than that it be asy to write fast code, in the language.
> I wouldn't mind that, as long as it isn't ridiculously hard or
> impossible to do the latter in the language.

It's hard to allow everything...

The combined effect of dynamic typing, passing function arguments in
C global variables, using a custom stack and stack overflow checking
caused the Ackermann function to be 5 times slower than in C.

-- 
   __("<         Marcin Kowalczyk
   \__/       qrczak@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15  8:59     ` Jon Harrop
  2005-03-15 20:17       ` Yoann Padioleau
@ 2005-03-31 11:41       ` Paul Argentoff
  1 sibling, 0 replies; 71+ messages in thread
From: Paul Argentoff @ 2005-03-31 11:41 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

Dear Jon Harrop,

Let JH = "Jon Harrop" in
  written_by JH => 

 JH> No, the OCaml code (compiled with ocamlopt) is much, much slower than
 JH> the C++.

Sorry, what?

-- 
Yours truly, WBR, Paul Argentoff.
Jabber:	paul@jabber.rtelekom.ru
RIPE:	PA1291-RIPE


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [Caml-list] OCaml troll on Slashdot
  2005-03-15 20:17       ` Yoann Padioleau
  2005-03-15 20:36         ` Jon Harrop
@ 2005-03-31 11:42         ` Paul Argentoff
  1 sibling, 0 replies; 71+ messages in thread
From: Paul Argentoff @ 2005-03-31 11:42 UTC (permalink / raw)
  To: Yoann Padioleau; +Cc: Jon Harrop, caml-list

Dear Yoann Padioleau,

Let YP = "Yoann Padioleau" in
  written_by YP => 

 YP> I have made the obvious optimization which is to replace the assoc
 YP> list by a Map (just changing 4 lines in the "troll" code), the ocaml
 YP> version is then far far faster.

A programmer is always the clue ;)

-- 
Yours truly, WBR, Paul Argentoff.
Jabber:	paul@jabber.rtelekom.ru
RIPE:	PA1291-RIPE


^ permalink raw reply	[flat|nested] 71+ messages in thread

* RE: [Caml-list] OCaml troll on Slashdot
@ 2005-03-18  6:04 Harrison, John R
  0 siblings, 0 replies; 71+ messages in thread
From: Harrison, John R @ 2005-03-18  6:04 UTC (permalink / raw)
  To: Marcin 'Qrczak' Kowalczyk, caml-list

| It's not the fault of the mapping function but of the stack being
| non-extensible. A user-written recursion can blow it too. Functional
| programming is supposed to encourage recursion, and a
non-tail-recursive
| 'map' is much more readable than alternatives.

Yes, I agree absolutely. I'm sure most users would be happier with the
occasional speed bump while the stack is extended than with uncaught
exceptions. And they'd be relieved of the need to recode trivial
functions with uglifying and time-wasting hacks to make them robust.

| My implementation of my language Kogut has extensible stack.
| And transparent bignums when appropriate. Yes, it's slower,
| but correctness is more important.

It's starting to sound like my dream language.

John.


^ permalink raw reply	[flat|nested] 71+ messages in thread

end of thread, other threads:[~2005-03-31 11:42 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-03-15  1:29 OCaml troll on Slashdot Karl Zilles
2005-03-15  8:32 ` [Caml-list] " Oliver Bandel
2005-03-15  8:45   ` Michael Vanier
2005-03-15  8:59     ` Jon Harrop
2005-03-15 20:17       ` Yoann Padioleau
2005-03-15 20:36         ` Jon Harrop
2005-03-15 21:03           ` padiolea
2005-03-15 21:40             ` William D.Neumann
2005-03-15 22:12               ` Yoann Padioleau
2005-03-15 23:07                 ` William D.Neumann
2005-03-15 23:39                   ` Jon Harrop
2005-03-15 23:54                     ` Thomas Fischbacher
2005-03-16  0:03                   ` Christopher Dutchyn
2005-03-16  0:18                   ` Oliver Bandel
2005-03-16  1:05                     ` Yoann Padioleau
2005-03-16  2:55                       ` Oliver Bandel
2005-03-16 11:23                         ` Thomas Fischbacher
2005-03-16 23:41                           ` Oliver Bandel
2005-03-16 13:33                         ` Yoann Padioleau
2005-03-16 23:59                           ` Oliver Bandel
2005-03-16  3:01                     ` Jon Harrop
2005-03-16 13:10                       ` Yoann Padioleau
2005-03-16 13:41                         ` Jacques Garrigue
2005-03-16 14:14                           ` Yoann Padioleau
2005-03-17  0:27                             ` Oliver Bandel
2005-03-16 17:43                           ` brogoff
2005-03-16 19:51                             ` Jon Harrop
2005-03-17  3:35                               ` brogoff
2005-03-17  3:48                                 ` Yaron Minsky
2005-03-17 10:16                                   ` Jon Harrop
2005-03-17 10:47                                     ` Oliver Bandel
2005-03-17 18:06                                     ` brogoff
2005-03-17 19:15                                       ` Marcin 'Qrczak' Kowalczyk
2005-03-18 17:46                                         ` brogoff
2005-03-18 18:44                                           ` Marcin 'Qrczak' Kowalczyk
2005-03-17 21:31                                       ` Oliver Bandel
2005-03-17  9:45                                 ` Christian Szegedy
2005-03-17 10:31                                 ` Jon Harrop
2005-03-17 11:11                                   ` Ville-Pertti Keinonen
2005-03-17 11:31                               ` tail-recursion vs. no tail-recursion in list functions sebastian.egner
2005-03-17 21:41                                 ` [Caml-list] " Oliver Bandel
2005-03-18  0:04                                   ` David Brown
2005-03-18  0:06                                   ` Karl Zilles
2005-03-18  1:13                                 ` Jacques Garrigue
2005-03-17  0:21                             ` [Caml-list] OCaml troll on Slashdot Oliver Bandel
2005-03-17  1:05                             ` Jacques Garrigue
2005-03-17 17:32                             ` Jason Hickey
2005-03-17 19:06                               ` Marcin 'Qrczak' Kowalczyk
2005-03-17  0:14                           ` Oliver Bandel
2005-03-16  1:38             ` Jacques Garrigue
2005-03-31 11:42         ` Paul Argentoff
2005-03-31 11:41       ` Paul Argentoff
2005-03-15 20:06   ` Yoann Padioleau
2005-03-15  9:25 ` Richard Jones
2005-03-15 10:08   ` YANG Shouxun
2005-03-15 20:02     ` Yoann Padioleau
2005-03-15 22:33       ` Richard Jones
2005-03-16  1:33       ` YANG Shouxun
2005-03-15 10:34   ` padiolea
2005-03-15 10:52     ` Diego Olivier Fernandez Pons
2005-03-15 14:12     ` Eijiro Sumii
2005-03-15 15:25       ` Christophe TROESTLER
2005-03-15 18:05         ` Thomas Fischbacher
2005-03-15 18:26           ` Kip Macy
2005-03-16  0:32             ` Oliver Bandel
2005-03-16 11:26             ` David Fox
2005-03-15 18:55         ` Christopher A. Watford
2005-03-15 19:56           ` Jon Harrop
2005-03-16  0:35             ` Oliver Bandel
2005-03-16  0:34           ` Oliver Bandel
2005-03-18  6:04 Harrison, John R

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).