LISP vs HASKELL vs PROLOG

  • Follow


I'm not trying to start a flame war about which one is the best. Could
anybody explain me each of these languages features and strong points ?
0
Reply eltoni.91 (22) 6/23/2009 10:23:09 PM

!!!@!!! wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

I know a bit Common Lisp, but I'm still lisp toddler. I can barely 
understand haskell, and have troubles reading prolog code.

So Common Lisp is multi-paradigm language - you can code in many 
different ways. Strong points are powerful macro system, continuous 
development cycle - e.g. you can modify the system while it's running, 
the multi-dispatch Common Lisp Object System (CLOS), the special global 
variables, lambdas, local variables (let), closures (let over lambdas), 
and many other things builtin, or built on top of it.

Common Lisp is not purely functional (unlike Haskell, and I think 
Prolog), and one can say not functional at all, but you can definitely 
code easily in functional matter, given you restrict yourself to 
non-destructive operations, and facilities such as FSet or similar.

Not being purely functional is both strong, and weak point. Strong, that 
you can really fix performance problems with iterative code where 
needed, weak that in generally allowing side-effects, you limit the 
compiler abilities - mainly the compiler cannot assume that data won't 
be modified. Not sure whether it's relevant :)

With Common Lisp you can quickly start prototyping code. Such code could 
be 10x-1000x less efficient than what you can actually achieve, but by 
iteratively profiling and applying hints and types to the compiler, you 
could gain a lot more. I'm still finding my way through this.

In general, there are reasonably good compilers there, where you won't 
need so much hints.

You can mend Common Lisp to your needs, as long as you become good 
master in it.

My weakest point for Common Lisp so far has been ME - I have to mend 
myself to the language, rather than trying to use it, the way I've been 
using past languages

As little as I know of Haskell, it's strictly-typed, lazy by default 
pure functional language (e.g. by default no side effects).

Can't say much about prolog.
0
Reply malkia1 (193) 6/23/2009 10:45:29 PM


!!!@!!! wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

Too late.
0
Reply fateman2 (331) 6/23/2009 11:18:01 PM

> In general, there are reasonably good compilers there, where you won't
> need so much hints.

Can you mention some of the best compilers?

> My weakest point for Common Lisp so far has been ME - I have to mend
> myself to the language, rather than trying to use it, the way I've been
> using past languages

I believe for me that's true, because if the past languages a
programmer has used were mainly imperative, than a different paradigm,
I guess, would require them to change the way mind thinks about
problems. I don't see programming just as a way for creating software
but as a whole different way of thinking about problems and solutions.
(Sometimes even in every-day life!).

I remember myself about two years ago when I decided to start learning
Haskell. I couldn't even understand the Hello World example.
Finally, after a week I gave up. Since then I have retried 3 other
times to learn Haskell and only the last time I had that bliss where
strangely, in a matter of milliseconds, like a hammer behind the head,
the code changed completely in front of my eyes and there it was like
truly it is, simple and beautiful and full with meaning like never
before. :)
Same thing happened me with Prolog too. I retried about 3 or 4 times
to learn it. But only after getting to understand Haskell, I suddenly
could understand Prolog too and strangely seemed so easy.

The reason for this, I believe, was that my mind was accustomed with
the imperative way of thinking and it needed some time (and perhaps
luck too!!!) to get the functional and logic as well.

Anyway thank you for your detailed response and god luck in mastering
Lisp ans Haskell.

Best regards,
Elton.
0
Reply eltoni.91 (22) 6/23/2009 11:23:39 PM

On Jun 24, 1:18=A0am, Richard Fateman <fate...@cs.berkeley.edu> wrote:
> !!!@!!! wrote:
> > I'm not trying to start a flame war about which one is the best. Could
> > anybody explain me each of these languages features and strong points ?
>
> Too late.

Richard, I'm not trying to start a debate here about which language is
the best, but I'm only looking forward to get informed about the
strong and weak points, similarities and distinctions between these
languages from a more experienced than me programmer.
Well, maybe the thread title could be confusing perhaps, I admit.
0
Reply eltoni.91 (22) 6/23/2009 11:28:37 PM

!!!@!!! wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?


This question reminds me of the Dilbert strip where the secretary asks
Dilbert to tell her everything she needs to know about engineering and
she doesn't care if it takes all day. Well, at least you didn't
cross-post it.

Have you heard of either Google or Wikipedia? Both are generally
considered good places to start when you want to expend as little effort
as possible to get some information.

http://en.wikipedia.org/wiki/Common_lisp
http://en.wikipedia.org/wiki/Haskell_(programming_language)
http://en.wikipedia.org/wiki/Prolog

Hope that helps,

Tom
0
Reply tmh.public (51) 6/23/2009 11:29:30 PM

On Jun 24, 1:29=A0am, "Thomas M. Hermann" <tmh.pub...@gmail.com> wrote:
> !!!@!!! wrote:
> > I'm not trying to start a flame war about which one is the best. Could
> > anybody explain me each of these languages features and strong points ?
>
> This question reminds me of the Dilbert strip where the secretary asks
> Dilbert to tell her everything she needs to know about engineering and
> she doesn't care if it takes all day. Well, at least you didn't
> cross-post it.
>
> Have you heard of either Google or Wikipedia? Both are generally
> considered good places to start when you want to expend as little effort
> as possible to get some information.
>
> http://en.wikipedia.org/wiki/Common_lisphttp://en.wikipedia.org/wiki/Hask=
ell_(programming_language)http://en.wikipedia.org/wiki/Prolog
>
> Hope that helps,
>
> Tom

Thank you Tom, but I have already tried Google and Wikipedia and they
have been more than helpful in some other way.
But if you read my last post, I'm looking to get information from
experiences in a more specific way, not from an encyclopedic-like
general way. I want to get information about the position of these
languages/tools in the software industry by their characteristics to
be more correct.

Elton.
0
Reply eltoni.91 (22) 6/23/2009 11:45:39 PM

!!!@!!! wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

Common Lisp is strict evaluation, dynamic typing with macros (to rewrite
code at compile-time) and run-time code evaluation. Was a pioneering
functional language decades ago but has long since been superceded. Has no
particular strengths today and, hence, is very rare. Main weaknesses are
baggage, poor performance, bad implementations and a really backward
community. The only notable development around Lisp for a decade is the new
programming language Clojure that runs on the JVM. In particular, Clojure
addressed many of Lisp's major problems by dropping the baggage, building
upon a performant VM with a concurrent GC and stealing all of the
intelligent members of the Lisp community.

Haskell is non-strict evaluation and static typing. Is a research language
used to implement many radical ideas that are unlikely to be of any
immediate use. Main strength is that it abstracts the machine away
entirely, allowing some solutions to be represented very concisely. Main
weakness is that it abstracts the machine away entirely, rendering
performance wildly unpredictable (will my elegant program terminate in my
lifetime? who knows...).

I know little about Prolog except that it was designed specifically for
logic programming (i.e. solving problems by specifying relations and
searching for solutions) and that some of our customers use it.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 6/24/2009 2:18:09 AM

On Jun 24, 12:23=A0am, "!!!@!!!" <eltoni...@gmail.com> wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

When student is ready the answer will arrive.

Slobodan Blazeski
0
Reply slobodan.blazeski (1459) 6/24/2009 7:30:24 AM

On 24 Giu, 00:23, "!!!@!!!" <eltoni...@gmail.com> wrote:
> ... which one is the best ...

You shall be informed that it's flies like YOU which some frog seems
irresistibly attracted by (and his tongue is long and slimy).

Game Over.

0
Reply java.oke (196) 6/24/2009 8:08:41 AM

On Tue, 23 Jun 2009 15:23:09 -0700, !!!@!!! wrote:

> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

Your question is still too specific.  Please try to be more general.
For example,

"Which one of Haskell, Prolog or CL is the best?"

gets a bonus mark for giving a vague criterion ("best") and no
context, but still constrains the answer to one of these three
languages.  It is better to ask

"Which is the best computer language?"

But we are still not there: your domain of meaningless optimization is
still too restricted.  Instead, ask:

"What is the best?"

Now the final touch: drop the criterion.  Ask it this way:

"What?"

HTH,

Tamas
0
Reply tkpapp (975) 6/24/2009 8:25:31 AM

On Jun 24, 12:23=A0am, "!!!@!!!" <eltoni...@gmail.com> wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

http://groups.google.com/group/comp.lang.lisp/msg/a5d5c10f811b81e8
...?
0
Reply larsnostdal (721) 6/24/2009 9:31:27 AM

On 23 June, 23:23, "!!!@!!!" <eltoni...@gmail.com> wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

In Qi (www.lambdassociates.org) all these, in a certain way, live
harmoniously together.  You would probably answer your question by
experimenting with Qi.

Mark
0
Reply dr.mtarver (661) 6/24/2009 1:20:42 PM

On Jun 24, 12:23 am, "!!!@!!!" <eltoni...@gmail.com> wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

Haskell is purely functional, very "formal", etc., Common Lisp has a
mighty object system and you can fit it to your needs in almost any
aspect, Prolog is a logical programming language. Comparing them is
like comparing mustard, apples and coffee.

Ask 10 people and you will get 11 opinions which one and why this one
is the best. As this is a Common Lisp usenet-group, it should be
expectable that most people prefer common lisp, for whatever reason.
0
Reply christoph.senjak (2) 6/24/2009 4:26:54 PM

On Jun 23, 6:23 pm, "!!!@!!!" <eltoni...@gmail.com> wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

The best way is to try each and read a lot about them, as everyone who
responds will have  a favorite language they are touting... Also,
certain languages will have varying amounts of power depending on the
person that you ask. Some people love common lisp and will tell you
all about how great it is, others get a headache from the parens and
haven't even written a line of code in it (but will tell you how
aweful it is anyway...).

A better thing to ask, 'what are your strong points', 'what are your
weak points', of each language community.

CL,
Pros:
+ old stable language,
+ multi-paradigm. (OO, functional, imperative, all in one).
+ macros
+ prototyping language (you can find the best algorithm fastest).
+ dynamic
+ faster than other dynamic languages (ruby/python) generally.

Cons:
- Not likely to change/improve
- Giving multi-paradigm language with macros to a bad programmer is
like giving a light sabre to a non-jedi, more likely to cut his arm
off and slice a hole in the side of the Millennium Falcon than save
Leia. (There is an amount of 'taste' involved, and not everyone has
it, even if they believe they do).
- Package system is crappy. (The package system is the real reason
people say 'there are no libraries for Common Lisp'. There are plenty
of libraries for common lisp, the problem is that they are a pain in
the ass to find/maintain and get working properly with other packages,
so you end up writing your own).
- Not quite as fast as statically typed Java/C most of the time

Neutrals:
+- If the library genuinely doesn't exist, you'll have a fun time
creating it.
   (seriously I enjoy writing lisp code and would probably do it even
if I weren't paid... just don't tell my boss).
+- Through macros you get an entirely new way of development through
DSLs and bottom up programming.
+- Community has some of the most well established and talented trolls
around.
+- A few months in you'll get this completely mind blowing experience
of 'getting it'.
0
Reply anonymous.c.lisper (176) 6/24/2009 4:46:58 PM

Mark Tarver wrote:
> On 23 June, 23:23, "!!!@!!!" <eltoni...@gmail.com> wrote:
>> I'm not trying to start a flame war about which one is the best. Could
>> anybody explain me each of these languages features and strong points ?
> 
> In Qi (www.lambdassociates.org) all these, in a certain way, live
> harmoniously together.  You would probably answer your question by
> experimenting with Qi.

How is Qi like Haskell?

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 6/24/2009 9:40:37 PM

On Jun 24, 4:18=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> stealing all of the intelligent members of the Lisp community.

I did not noticed anything like this, all smart lispers whose blogs i
read are still active, in fact they are so smart so bunch of them dont
post on c.l.l. ... also Clojure didnt stole you from us and that is a
real pity
0
Reply milanj (42) 6/25/2009 6:42:16 AM

On Jun 24, 4:18=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> !!!@!!! wrote:
> > I'm not trying to start a flame war about which one is the best. Could
> > anybody explain me each of these languages features and strong points ?
>
> Common Lisp is strict evaluation, dynamic typing with macros (to rewrite
> code at compile-time) and run-time code evaluation. Was a pioneering
> functional language decades ago but has long since been superceded. Has n=
o
> particular strengths today and, hence, is very rare. Main weaknesses are
> baggage, poor performance, bad implementations and a really backward
> community. The only notable development around Lisp for a decade is the n=
ew
> programming language Clojure that runs on the JVM. In particular, Clojure
> addressed many of Lisp's major problems by dropping the baggage, building
> upon a performant VM with a concurrent GC and stealing all of the
> intelligent members of the Lisp community.
>
> Haskell is non-strict evaluation and static typing. Is a research languag=
e
> used to implement many radical ideas that are unlikely to be of any
> immediate use. Main strength is that it abstracts the machine away
> entirely, allowing some solutions to be represented very concisely. Main
> weakness is that it abstracts the machine away entirely, rendering
> performance wildly unpredictable (will my elegant program terminate in my
> lifetime? who knows...).
>
> I know little about Prolog except that it was designed specifically for
> logic programming (i.e. solving problems by specifying relations and
> searching for solutions) and that some of our customers use it.
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy.com=
/?u

I feel so sorry for you.
0
Reply Karol.Skocik (148) 6/25/2009 9:05:58 AM

On Jun 23, 6:23=A0pm, "!!!@!!!" <eltoni...@gmail.com> wrote:
> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong points ?

Common Lisp is so much more useful than either Prolog or Haskell that
it isn't even funny.

Why, if I want to do something in Common Lisp, I can open up a
terminal window, type "clisp", open another terminal window and type
"vim"[1] and start putting together something useful out of the
standard functions and a few essential libraries, all of which I'm
pretty familiar with.

OTOH, if I wanted to do something in Prolog, I'd have to download a
Prolog implementation, install it, read a book or two on Prolog,
probably do a bunch of exercises and little warm-up projects, and then
maybe I'd be able to put together something useful. Haskell would be
the same.

So, yeah, Common Lisp: way better than those other languages you're
talking about.

Cheers, 0
Pillsy

[1] That's on my work computer; at home I use SLIME + SBCL and things
are even more pleasant.
0
Reply pillsbury (453) 6/25/2009 1:53:41 PM

On Jun 25, 3:53=A0pm, Pillsy <pillsb...@gmail.com> wrote:
> On Jun 23, 6:23=A0pm, "!!!@!!!" <eltoni...@gmail.com> wrote:
>
> > I'm not trying to start a flame war about which one is the best. Could
> > anybody explain me each of these languages features and strong points ?
>
> Common Lisp is so much more useful than either Prolog or Haskell that
> it isn't even funny.
>
> Why, if I want to do something in Common Lisp, I can open up a
> terminal window, type "clisp", open another terminal window and type
> "vim"[1] and start putting together something useful out of the
> standard functions and a few essential libraries, all of which I'm
> pretty familiar with.
>
> OTOH, if I wanted to do something in Prolog, I'd have to download a
> Prolog implementation, install it, read a book or two on Prolog,
> probably do a bunch of exercises and little warm-up projects, and then
> maybe I'd be able to put together something useful. Haskell would be
> the same.
>
> So, yeah, Common Lisp: way better than those other languages you're
> talking about.
>
> Cheers, 0
> Pillsy
>
> [1] That's on my work computer; at home I use SLIME + SBCL and things
> are even more pleasant.

Yeah, somehow I feel the same about CL. But there's something with
Haskell that atracts me and makes me believe that maybe there'll be
something promising.

I use the same setup SLIME + SBCL and I'm really starting to love
Emacs.
0
Reply eltoni.91 (22) 6/25/2009 2:52:38 PM

On Jun 25, 9:53=A0am, Pillsy <pillsb...@gmail.com> wrote:
> On Jun 23, 6:23=A0pm, "!!!@!!!" <eltoni...@gmail.com> wrote:
>
> > I'm not trying to start a flame war about which one is the best. Could
> > anybody explain me each of these languages features and strong points ?
>
> Common Lisp is so much more useful than either Prolog or Haskell that
> it isn't even funny.
>
> Why, if I want to do something in Common Lisp, I can open up a
> terminal window, type "clisp", open another terminal window and type
> "vim"[1] and start putting together something useful out of the
> standard functions and a few essential libraries, all of which I'm
> pretty familiar with.
>
> OTOH, if I wanted to do something in Prolog, I'd have to download a
> Prolog implementation, install it, read a book or two on Prolog,
> probably do a bunch of exercises and little warm-up projects, and then
> maybe I'd be able to put together something useful. Haskell would be
> the same.
>
> So, yeah, Common Lisp: way better than those other languages you're
> talking about.
>
> Cheers, 0
> Pillsy
>
> [1] That's on my work computer; at home I use SLIME + SBCL and things
> are even more pleasant.

"Common lisp, I know it and its already installed, therefore its
better than everything else!"

:-P

(Not that I don't agree with you) :-)
0
Reply anonymous.c.lisper (176) 6/26/2009 4:29:31 AM

milanj wrote:
> On Jun 24, 4:18 am, Jon Harrop <j...@ffconsultancy.com> wrote:
>> stealing all of the intelligent members of the Lisp community.
> 
> I did not noticed anything like this, all smart lispers whose blogs i
> read are still active, in fact they are so smart so bunch of them dont
> post on c.l.l. ... also Clojure didnt stole you from us and that is a
> real pity

Actually Clojure did steal me: they are requesting that I write books on
Clojure. Obviously I'm not going to waste my time writing books for CL...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/3/2009 9:55:24 PM

Jon Harrop wrote:
> milanj wrote:
>> On Jun 24, 4:18 am, Jon Harrop <j...@ffconsultancy.com> wrote:
>>> stealing all of the intelligent members of the Lisp community.
>> I did not noticed anything like this, all smart lispers whose blogs i
>> read are still active, in fact they are so smart so bunch of them dont
>> post on c.l.l. ... also Clojure didnt stole you from us and that is a
>> real pity
> 
> Actually Clojure did steal me: they are requesting that I write books on
> Clojure. 

Reminds me of when my older brother would say he heard Mom calling me so 
I would go away and leave him and his friends alone.

Don't fall for it, Jon!

kzo
0
Reply kentilton (2964) 7/4/2009 4:25:30 PM

On 24 June, 22:40, Jon Harrop <j...@ffconsultancy.com> wrote:
> Mark Tarver wrote:
> > On 23 June, 23:23, "!!!@!!!" <eltoni...@gmail.com> wrote:
> >> I'm not trying to start a flame war about which one is the best. Could
> >> anybody explain me each of these languages features and strong points =
?
>
> > In Qi (www.lambdassociates.org) all these, in a certain way, live
> > harmoniously together. =A0You would probably answer your question by
> > experimenting with Qi.
>
> How is Qi like Haskell?
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy.com=
/?u

Qi is close enough to Haskell in enough salient ways for this guy to
get an answer to his question by experiment.  And he can mix and match
all these paradigms in one environment to get an answer he will find
convincing to him - which is probably the best way to learn.
0
Reply dr.mtarver (661) 7/5/2009 10:28:40 PM

On Jul 3, 5:55=A0pm, JH wrote:
> milanj wrote:
> > On Jun 24, 4:18=A0am, JH wrote:
> >> stealing all of the intelligent members of the Lisp community.
>
> > I did not noticed anything like this, all smart lispers whose blogs i
> > read are still active, in fact they are so smart so bunch of them dont
> > post on c.l.l. ... also Clojure didnt stole you from us and that is a
> > real pity
>
> Actually Clojure did steal me: they are requesting that I write books on
> Clojure. Obviously I'm not going to waste my time writing books for CL...
>
> --

Agreed, no money in writing books for CL when there are already so
many good ones that are in the public domain or otherwise already
written. I mean, anyone who reads this group or reddit regularly knows
that you have a real hard-on for CL but just couldn't cut it our book
market.

But JH, you have to consider the consequences of this 'Clojure Book'.

1.) I will still /not/ buy it, because it is written by you.

2.) You will be (potentially forced) to make troll and spam posts that
are actually on topic.

3.) You might have to concede that there are good parts of common
lisp. (Stuff you cannot do easily in Ocaml or F#).
0
Reply anonymous.c.lisper (176) 7/7/2009 11:11:34 AM

On Jul 7, 7:11=A0am, ACL <anonymous.c.lis...@gmail.com> wrote:
> On Jul 3, 5:55=A0pm, JH wrote:
>
> > milanj wrote:
> > > On Jun 24, 4:18=A0am, JH wrote:
> > >> stealing all of the intelligent members of the Lisp community.
>
> > > I did not noticed anything like this, all smart lispers whose blogs i
> > > read are still active, in fact they are so smart so bunch of them don=
t
> > > post on c.l.l. ... also Clojure didnt stole you from us and that is a
> > > real pity
>
> > Actually Clojure did steal me: they are requesting that I write books o=
n
> > Clojure. Obviously I'm not going to waste my time writing books for CL.=
...
>
> > --
>
> Agreed, no money in writing books for CL when there are already so
> many good ones that are in the public domain or otherwise already
> written. I mean, anyone who reads this group or reddit regularly knows
> that you have a real hard-on for CL but just couldn't cut it our book
> market.
>
I think he also likes Haskell more than he is willing to admit.


0
Reply larryliberty (26) 7/7/2009 12:12:21 PM

ACL <anonymous.c.lisper@gmail.com> writes:

> Agreed, no money in writing books for CL when there are already so
> many good ones that are in the public domain or otherwise already
> written.

However, one book that I eagerly await is Conrad Barski's "Land of Lisp"
which seems to linger in some limbo state.  I think I'll preorder it in the
hope that this will speed things up a bit.

Nicolas

[To ACL: Sorry for replying by email first.]

0
Reply lastname7788 (201) 7/7/2009 3:50:35 PM

On Jul 7, 5:50=A0pm, Nicolas Neuss <lastn...@math.uni-karlsruhe.de>
wrote:
> ACL <anonymous.c.lis...@gmail.com> writes:
> > Agreed, no money in writing books for CL when there are already so
> > many good ones that are in the public domain or otherwise already
> > written.
>
> However, one book that I eagerly await is Conrad Barski's "Land of Lisp"
> which seems to linger in some limbo state. =A0I think I'll preorder it in=
 the
> hope that this will speed things up a bit.
>
> Nicolas
>
> [To ACL: Sorry for replying by email first.]

Don't forget Nick Levine's Lisp outside the Box  http://lisp-book.org/

Slobodan
http://www.linkedin.com/in/slobodanblazeski
0
Reply slobodan.blazeski (1459) 7/8/2009 10:58:25 AM

Nicolas Neuss wrote:
> ACL <anonymous.c.lisper@gmail.com> writes:
>> Agreed, no money in writing books for CL when there are already so
>> many good ones that are in the public domain or otherwise already
>> written.
> 
> However, one book that I eagerly await is Conrad Barski's "Land of Lisp"
> which seems to linger in some limbo state.

Why do you eagerly await it?

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/8/2009 10:47:49 PM

Larry Coleman wrote:
> I think he also likes Haskell more than he is willing to admit.

Sure, they all have their merits but none of them have what I want right
now.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/8/2009 10:48:47 PM

On Jun 24, 1:23=A0am, "!!!@!!!" <eltoni...@gmail.com> wrote:
> > In general, there are reasonably good compilers there, where you won't
> > need so much hints.
>
> Can you mention some of the best compilers?
>
> > My weakest point for Common Lisp so far has been ME - I have to mend
> > myself to the language, rather than trying to use it, the way I've been
> > using past languages
>
> I believe for me that's true, because if the past languages a
> programmer has used were mainly imperative, than a different paradigm,
> I guess, would require them to change the way mind thinks about
> problems. I don't see programming just as a way for creating software
> but as a whole different way of thinking about problems and solutions.
> (Sometimes even in every-day life!).
>
> I remember myself about two years ago when I decided to start learning
> Haskell. I couldn't even understand the Hello World example.
> Finally, after a week I gave up. Since then I have retried 3 other
> times to learn Haskell and only the last time I had that bliss where
> strangely, in a matter of milliseconds, like a hammer behind the head,
> the code changed completely in front of my eyes and there it was like
> truly it is, simple and beautiful and full with meaning like never
> before. :)
> Same thing happened me with Prolog too. I retried about 3 or 4 times
> to learn it. But only after getting to understand Haskell, I suddenly
> could understand Prolog too and strangely seemed so easy.
>
> The reason for this, I believe, was that my mind was accustomed with
> the imperative way of thinking and it needed some time (and perhaps
> luck too!!!) to get the functional and logic as well.
>
> Anyway thank you for your detailed response and god luck in mastering
> Lisp ans Haskell.
>
> Best regards,
> Elton.

A good way to remove the imperative way of thinking is reading "How To
Design Programs" and doing the exercises. It uses Scheme and is really
a good book to transition from imperative languages to more functional
languages.

Regards,

Jurgen
0
Reply jurgen.defurne1 (118) 7/9/2009 8:09:00 AM

On Jun 25, 4:52=A0pm, "!!!@!!!" <eltoni...@gmail.com> wrote:
> On Jun 25, 3:53=A0pm, Pillsy <pillsb...@gmail.com> wrote:
>
>
>
> > On Jun 23, 6:23=A0pm, "!!!@!!!" <eltoni...@gmail.com> wrote:
>
> > > I'm not trying to start a flame war about which one is the best. Coul=
d
> > > anybody explain me each of these languages features and strong points=
 ?
>
> > Common Lisp is so much more useful than either Prolog or Haskell that
> > it isn't even funny.
>
> > Why, if I want to do something in Common Lisp, I can open up a
> > terminal window, type "clisp", open another terminal window and type
> > "vim"[1] and start putting together something useful out of the
> > standard functions and a few essential libraries, all of which I'm
> > pretty familiar with.
>
> > OTOH, if I wanted to do something in Prolog, I'd have to download a
> > Prolog implementation, install it, read a book or two on Prolog,
> > probably do a bunch of exercises and little warm-up projects, and then
> > maybe I'd be able to put together something useful. Haskell would be
> > the same.
>
> > So, yeah, Common Lisp: way better than those other languages you're
> > talking about.
>
> > Cheers, 0
> > Pillsy
>
> > [1] That's on my work computer; at home I use SLIME + SBCL and things
> > are even more pleasant.
>
> Yeah, somehow I feel the same about CL. But there's something with
> Haskell that atracts me and makes me believe that maybe there'll be
> something promising.
>
> I use the same setup SLIME + SBCL and I'm really starting to love
> Emacs.

There used to be 'Two Dozen Short Lessons in Haskell' on the Internet,
but now it has become a book and you cannot find it anymore. I do have
an old version though, if you are interested.

Regards,

Jurgen
0
Reply jurgen.defurne1 (118) 7/9/2009 8:19:57 AM

Jon Harrop <jon@spammershome.com> writes:

> Nicolas Neuss wrote:

>> However, one book that I eagerly await is Conrad Barski's "Land of Lisp"
>> which seems to linger in some limbo state.
>
> Why do you eagerly await it?

Hmm, good question.  I think I like his Lisp alien, the "Lisp is different"
cartoon and the Macro short course on http://www.lisperati.com/casting.html
at least sufficiently much that I would like to buy and take a look at the
book.

Nicolas
0
Reply lastname7788 (201) 7/9/2009 9:48:29 AM

On Jul 8, 6:48=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > I think he also likes Haskell more than he is willing to admit.
>
> Sure, they all have their merits but none of them have what I want right
> now.
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy.com=
/?u

This raises a question of the kind that I generally don't ask because
I know in advance that I won't like the answer:

So what do you want from a programming language?
0
Reply larryliberty (26) 7/9/2009 12:15:14 PM

On Jun 23, 7:18 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> !!!@!!! wrote:
> > I'm not trying to start a flame war about which one is the best. Could
> > anybody explain me each of these languages features and strong points ?
>
> Common Lisp is strict evaluation, dynamic typing with macros (to rewrite
> code at compile-time) and run-time code evaluation. Was a pioneering
> functional language decades ago but has long since been superceded. Has n=
o
> particular strengths today and, hence, is very rare. Main weaknesses are
> baggage, poor performance, bad implementations and a really backward
> community. The only notable development around Lisp for a decade is the n=
ew
> programming language Clojure that runs on the JVM. In particular, Clojure
> addressed many of Lisp's major problems by dropping the baggage, building
> upon a performant VM with a concurrent GC and stealing all of the
> intelligent members of the Lisp community.
>
> Haskell is non-strict evaluation and static typing. Is a research languag=
e
> used to implement many radical ideas that are unlikely to be of any
> immediate use. Main strength is that it abstracts the machine away
> entirely, allowing some solutions to be represented very concisely. Main
> weakness is that it abstracts the machine away entirely, rendering
> performance wildly unpredictable (will my elegant program terminate in my
> lifetime? who knows...).
>
> I know little about Prolog except that it was designed specifically for
> logic programming (i.e. solving problems by specifying relations and
> searching for solutions) and that some of our customers use it.

i heartily disagree.

In my opinion:

=E2=80=A2 lisp =3D useless old shit.

=E2=80=A2 haskell =3D useless academic shit.

=E2=80=A2 prolog =3D useless old and academic shit.

=E2=80=A2 Qi Lisp =3D Academically confined. Esoteric. Abtruse. Unreadible.
Doomed.

=E2=80=A2 Clojure lisp =3D of little future due to competition.

=E2=80=A2 Mathematica =3D Widely used. Wildly successful. witness A New Kin=
da
Science & Wolfram Alpha.

=E2=80=A2 OCaml =3D Widely used. Wildly successful. Almost all formal proof
systems that are actively used are written in OCaml. And Microsoft
giant's version of OCaml, the F#, with .NET, is about to wipe out the
planet of imperative monkies.

References:

=E2=80=A2 Language, Purity, Cult, and Deception
  http://xahlee.org/UnixResource_dir/writ/lang_purity_cult_deception.html

=E2=80=A2 Proliferation of Computing Languages
  http://xahlee.org/UnixResource_dir/writ/new_langs.html

=E2=80=A2 What Languages to Hate
  http://xahlee.org/UnixResource_dir/writ/language_to_hate.html

=E2=80=A2 Xah's OCaml Tutorial
  http://xahlee.org/ocaml/ocaml.html

  Xah
=E2=88=91 http://xahlee.org/

=E2=98=84
0
Reply xahlee (818) 7/9/2009 6:29:42 PM

Xah Lee <xahlee@gmail.com> wrote on Thu, 9 Jul 2009 :
> In my opinion:
> lisp = useless old shit.

So, why do you post on this newsgroup, c.l.l?  It's clearly for people who
are interested in Lisp.  If you're not, why are you here?
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               don@geddis.org
Men occasionally stumble over the truth, but most of them pick themselves up
and hurry off as if nothing had happened.  -- Winston Churchill (1874-1965)
0
Reply don8867 (556) 7/9/2009 8:22:08 PM

Larry Coleman wrote:
> So what do you want from a programming language?

Excellent question. I've never really tried to enumerate it before...

Performance: the predictably-excellent performance of OCaml but with
monomorphization during JIT to remove the overhead of polymorphism and with
F#-style inlined HOFs to facilitate efficient abstraction. OCaml's x64
codegen is awesome but its x86 codegen leaves a lot of room for
improvement. However, MLton, SMLNJ, GHC, SBCL, Bigloo etc. don't seem to be
any better (except perhaps for the SSE support just added to SBCL but I
haven't tried it yet).

Data representation: should be as close to C as possible for easy interop.
For example, tuples should be C structs (at the expense of polymorphic
recursion).

Interoperability: use JIT compilation as Lisp and .NET do, with FFI code
defined entirely in the HLL.

Syntax: Indentation-sensitive syntax as in Python, Haskell and F# was a huge
design mistake because cut'n'paste from a browser can break code
semantically by altering the indentation, and it prohibits autoindentation
leaving you to reindent huge swaths of code by hand. Lisps got it wrong by
oversimplifying the syntax, making math particularly cumbersome. OCaml got
it wrong mainly by being too complex (e.g. a dozen different kinds of
brackets instead of consistent brackets and identifiers to distinguish
between lists, arrays, streams etc.) and by using unconventional operators
(e.g. ** for power and ^ for string concatenation).

Macros: can be nice but they're abused far more often than they're used.
Missing language features should be fixed at source in the compiler instead
of being retrofitted in an ad-hoc way using macros. OCaml and Lisp are both
bad for this but it is still better that being stuck with limitations as in
SML and Haskell.

Parallelism: wait-free work-stealing deques like Cilk and Microsoft's TPL.

Concurrent GC: OCaml and Python could not be worse in this respect. Haskell
(and SBCL?) are slightly better with parallel but non-concurrent
collectors. The JVM and CLR (especially in .NET 3.5 SP1) are the gold
standard, of course.

Libraries: Nothing on Linux comes close to Windows Presentation Foundation
for robustly-deployable hardware accelerated UIs but open source
computational libraries on Linux put even the most expensive commercial
offerings on Windows to shame. I'd like the best of both worlds in the
standard library and running reliably on *lots* of machines.

Interface: I want a Mathematica notebook interface with typesetting and
integrated visualization instead of plain text.

Type system: OCaml's static type system is invaluable but OCaml lacks
generic typesetting, type-safe serialization and type classes. Optional
dynamic typing can also be valuable, e.g. we're now using it in our F#
products to make the REPL easier to use:

http://fsharpnews.blogspot.com/2009/06/f-for-visualization-0400-released.html

FWIW, I'm going to try to implement as much of this as possible in HLVM:

http://hlvm.forge.ocamlcore.org/

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/9/2009 11:32:57 PM

On Fri, 10 Jul 2009 00:32:57 +0100, Jon Harrop <jon@ffconsultancy.com> said:
> ...
> unconventional operators (e.g. ** for power ...)

  That is an at-least-55-year-old convention.  How much more
  conventional can it get?

  ---Vassil.


-- 
"Even when the muse is posting on Usenet, Alexander Sergeevich?"
0
Reply vnikolov1 (276) 7/10/2009 7:03:21 AM

"!!!@!!!" <eltoni.91@gmail.com> writes:

> I'm not trying to start a flame war about which one is the best. Could
> anybody explain me each of these languages features and strong
 > points ?
Then the question should not be Lisp vs Haskell vs Prolog but 
Lisp and  Haskell and Prolog, which to use when?



-- 
Please remove just-for-news- to reply via e-mail.
0
Reply just-for-news-frido (314) 7/10/2009 7:38:03 AM

!!!@!!! wrote:

> Thank you Tom, but I have already tried Google and Wikipedia and they
> have been more than helpful in some other way.
> But if you read my last post, I'm looking to get information from
> experiences in a more specific way, not from an encyclopedic-like
> general way. I want to get information about the position of these
> languages/tools in the software industry by their characteristics to
> be more correct.

Ok, let's start a discussion, there are really too few language flame wars
in this newsgroup :-)

Wikipedia says a bit about applications in Common Lisp:

http://en.wikipedia.org/wiki/Common_lisp#Applications

It doesn't mention that this is the complete list of bigger applications
ever written in Lisp and even Jak and Daxter was not Common Lisp.

Lisp isn't used very much in the software industry. Most of the time C,
Java, Python, PHP and other mainstream languages are used, see e.g. the
projects on Sourceforge. There are 197 Prolog projects, 492 Lisp projects,
120 Haskell projects, but for example 42832 Java projects, 32420 C
projects, 28828 PHP projects and 13412 Python projects:

http://sourceforge.net/softwaremap/trove_list.php?form_cat=177
http://sourceforge.net/softwaremap/trove_list.php?form_cat=170
http://sourceforge.net/softwaremap/trove_list.php?form_cat=451
http://sourceforge.net/softwaremap/trove_list.php?form_cat=198
http://sourceforge.net/softwaremap/trove_list.php?form_cat=164
http://sourceforge.net/softwaremap/trove_list.php?form_cat=183
http://sourceforge.net/softwaremap/trove_list.php?form_cat=178

I assume this reflects the number of programmers who used this in the
software industry as well, so Lisp or Haskell are using only about 2% of
all programmers.

This is dangeraous for big companies, because there are not enough people
who can write and maintain good software in these languages, which is the
reason why e.g. Yahoo store was rewritten in C and Perl or why Naugthy Dog
are using C++ now:

http://www.gamasutra.com/features/20020710/white_03.htm

Personally I know of a project for an insurance company which was written
in Prolog for risk analysis. After the programmer left the company, nobody
could understand and maintain the system, so it was rewritten in Java.

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/10/2009 7:42:46 AM

On Fri, 10 Jul 2009 09:42:46 +0200, Frank Buss <fb@frank-buss.de> said:
> ...
> Personally I know of a project for an insurance company which was written
> in Prolog for risk analysis. After the programmer left the company, nobody
> could understand and maintain the system, so it was rewritten in Java.

    He had bought a large map representing the sea
    Without the least vestige of land
    And the crew were all happy as they found it to be
    A map they could all understand.

  (Fit the Second, I think, quoting from memory.)

  ---Vassil,
  who couldn't resist...


-- 
"Even when the muse is posting on Usenet, Alexander Sergeevich?"
0
Reply vnikolov1 (276) 7/10/2009 8:04:15 AM

Jon Harrop wrote:

> Libraries: Nothing on Linux comes close to Windows Presentation Foundation
> for robustly-deployable hardware accelerated UIs 

Do you know Qt and wxWidgets? Both libraries are really nice and the GUI
editor for Qt is as complete as for WPF, but if you are using layout
managers, you can't do bugs like this one with the buttons in the bottom
area, found in Microsoft Visual Studio 2008:

http://www.frank-buss.de/tmp/gui-bug.jpg

I don't know if Microsoft practices "eat your own dogfood" and if they are
using WPF, but this is not a good publicity for their framework.

wxWidgets has some nice GUI editors, too and it uses the native controls of
the operating system, so I assume they are hardware accelerated, but why is
this important for a GUI, if you just want to display some text and edit
fields and not realtime 3D animation?

Qt is available as LGPL, now that Nokia bought Trolltech for Windows (last
year it was available for Windows as commercial, only). wxWidget is
available for Win32, Mac OS X, GTK+, X11, Motif, WinCE, and more, and has a
LPGL-like licence.

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/10/2009 8:06:26 AM

On Jul 9, 4:32=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > So what do you want from a programming language?
>
> Excellent question. I've never really tried to enumerate it before...

(snip)

This "being functional" is an unhealthy obsession. 3/4 of the time
imperative idioms are more convenient, and 1/4 of the time functional
ones are more convenient.

But because most popular languages are imperative, people are whining
about those 1/4 cases and some disturbed individuals even think
languages should be pure-functional.

What I want is a safe (or has an option to be safe), fast mostly
imperative language that doesn't suck.

C++ (if you are very good and very careful), Java and OCaml are
decent, but not quite what I want. Maybe D and Ada, although I don't
know about those.
0
Reply fft1976 (100) 7/10/2009 8:10:49 AM

On 10 Jul., 09:42, Frank Buss <f...@frank-buss.de> wrote:
> !!!@!!! wrote:
> > Thank you Tom, but I have already tried Google and Wikipedia and they
> > have been more than helpful in some other way.
> > But if you read my last post, I'm looking to get information from
> > experiences in a more specific way, not from an encyclopedic-like
> > general way. I want to get information about the position of these
> > languages/tools in the software industry by their characteristics to
> > be more correct.
>
> Ok, let's start a discussion, there are really too few language flame wars
> in this newsgroup :-)
>
> Wikipedia says a bit about applications in Common Lisp:
>
> http://en.wikipedia.org/wiki/Common_lisp#Applications
>
> It doesn't mention that this is the complete list of bigger applications
> ever written in Lisp and even Jak and Daxter was not Common Lisp.

Nice try Frank. Fine to get this discussion going for the nth time.
But please try not to follow 'Harrop' style, post wrong things and
wait for people to correct it.

You should come to the Lisp meeting organized by Edi Weitz and Arthur
Lemmens
in Hamburg: http://weitz.de/eclm2009/

I'm pretty sure several people can tell you a bit about the
applications
they are writing or have written. If you were a bit more familiar with
the
domains Common Lisp is used mostly, you would know that there
are thousands of applications written in Common Lisp. That you don't
know them does not mean they don't exist.

Btw.: the DEVELOPMENT ENVIRONMENT for Jak and Daxter was written in
Common Lisp. It included a compiler for a Scheme like language,
which runs on the Playstation 2.

....

> This is dangeraous for big companies, because there are not enough people
> who can write and maintain good software in these languages, which is the
> reason why e.g. Yahoo store was rewritten in C and Perl or why Naugthy Dog
> are using C++ now:
>
> http://www.gamasutra.com/features/20020710/white_03.htm

Naughty Dog says this about their decision not to use Lisp for the
Playstation 3:

"In all honesty, the biggest reason we're not using GOAL for next-gen
development is because we're now part of Sony. I can only imagine
Sony's shock when they purchased Naughty Dog a few years back, hoping
to be able to leverage some of our technology across other Sony
studios, and then realized that there was no way anyone else would be
able to use any of our codebase. :)

Sony wants us to be able to share code with other studios, and this
works both ways - both other studios using our code and vice versa.
Add this to the difficulty curve of learning a new language for new
hires, lack of support from external development tools (we had our own
compiler, linker, and debugger, and pretty much had to use Emacs as
our IDE), etc, means that there are clearly a lot of other factors
involved. Note, however, that these issues aren't really technical
problems, they're social ones.

I can definitively say that the investment in GOAL was worth it for
our PS2 titles, despite the initial setup time and maintenance. Our
productivity gains were huge, and were more than worth the time
investment. This time around, however, the circumstances aren't quite
the same. If we were still an independent studio, I'm almost positive
we'd be extending GOAL for the next-generation of development. As it
is, we are looking into alternative approaches (custom preprocessors,
assemblers, linkers, you name it) - but all of these approaches fall
short in many ways of the unified language and environment we had with
GOAL.

That said, if there was a serious effort on the part of the game
development community to develop and standardize a language for game
development, everyone could gain the benefits without suffering the
drawbacks (lack of code-sharing, learning curve, etc). And if there's
enough community support, it would only be a matter of time before
some really high-quality commercial tools came out to work with the
language."


But now Naughty Dog uses Scheme again.

  http://www.naughtydog.com/corporate/press/GDC%202008/AdventuresInDataCompilation.pdf

>
> Personally I know of a project for an insurance company which was written
> in Prolog for risk analysis. After the programmer left the company, nobody
> could understand and maintain the system, so it was rewritten in Java.
>
> --
> Frank Buss, f...@frank-buss.dehttp://www.frank-buss.de,http://www.it4-systems.de

0
Reply joswig8642 (2198) 7/10/2009 8:21:28 AM

fft1976 wrote:

> What I want is a safe (or has an option to be safe), fast mostly
> imperative language that doesn't suck.
> 
> C++ (if you are very good and very careful), Java and OCaml are
> decent, but not quite what I want. Maybe D and Ada, although I don't
> know about those.

You could try Common Lisp: It is nice for imperative code and doesn't suck
as much as C++ for functional code :-)

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/10/2009 8:23:46 AM

On Jul 10, 1:23=A0am, Frank Buss <f...@frank-buss.de> wrote:
> fft1976 wrote:
> > What I want is a safe (or has an option to be safe), fast mostly
> > imperative language that doesn't suck.
>
> > C++ (if you are very good and very careful), Java and OCaml are
> > decent, but not quite what I want. Maybe D and Ada, although I don't
> > know about those.
>
> You could try Common Lisp: It is nice for imperative code and doesn't suc=
k
> as much as C++ for functional code :-)
>

It's probably inconceivable to you, but I, like 99.9% of other
programmers, respectfully disagree.
0
Reply fft1976 (100) 7/10/2009 8:34:49 AM

On Jul 10, 10:34=A0am, fft1976 <fft1...@gmail.com> wrote:
> On Jul 10, 1:23=A0am, Frank Buss <f...@frank-buss.de> wrote:
>
> > fft1976 wrote:
> > > What I want is a safe (or has an option to be safe), fast mostly
> > > imperative language that doesn't suck.
>
> > > C++ (if you are very good and very careful), Java and OCaml are
> > > decent, but not quite what I want. Maybe D and Ada, although I don't
> > > know about those.
>
> > You could try Common Lisp: It is nice for imperative code and doesn't s=
uck
> > as much as C++ for functional code :-)
>
> It's probably inconceivable to you, but I, like 99.9% of other
> programmers, respectfully disagree.

I hope you don't disagree about C++ sucking at functional
programming... so you must disagree about Lisp being nice at
imperative code. While for heavily imperative algorithms, C-like
languages are likely to be more compact than Lisp (whether this
implies "more readable" depends on the reader), I find in my
experience with Java, and C++ shouldn't be much different, that in
practice heavily imperative code tends to be scarcer than what people
commonly think. Most of my Java methods are less than 20 lines long,
many are shorter. And of those lines, half or so at least are calls to
other methods, not loops or assignments or increments etc.

Maybe your experience is different. But for me, Lisp is more than fine
for occasional imperative code. Of course, if you try to write C in
Lisp it will come out pretty horrible, just like if you try to write
Lisp in Java (sigh...).

Cheers,
Alessio
0
Reply alessiostalla (364) 7/10/2009 9:19:45 AM

Rainer Joswig wrote:

> You should come to the Lisp meeting organized by Edi Weitz and Arthur
> Lemmens
> in Hamburg: http://weitz.de/eclm2009/

Thanks, but my focus has shifted a bit. Currently I'm trying to learn piano
playing in my spare time :-)

http://www.youtube.com/user/frankbuss

and sometimes doing some interesting computing stuff, e.g. magnetic flux
calculation with graphics cards:

http://groups.google.com/group/de.sci.electronics/browse_thread/thread/619614473c54d3df

> I'm pretty sure several people can tell you a bit about the
> applications
> they are writing or have written. If you were a bit more familiar with
> the
> domains Common Lisp is used mostly, you would know that there
> are thousands of applications written in Common Lisp. That you don't
> know them does not mean they don't exist.

You are right, this was a bit exaggerated by me. But the point is that
there are millions of applications in C-like languages, so I think at least
it is true, that there are less than 2% Lisp programmers and programs. Of
course, this doesn't mean that C is better than Lisp. It is better, if you
want to get a programming job, but if you are a good Lisp and a good C
programmer, I think it is easier to implement a given problem in Lisp.

> But now Naughty Dog uses Scheme again.
> 
>   http://www.naughtydog.com/corporate/press/GDC%202008/AdventuresInDataCompilation.pdf

I don't see that they are using it again. They write that they are planning
to use it ("We will build DC in Scheme") and the presentation has some C++
examples, too, so looks like it will be a mix of Scheme and C++, using the
Scheme part for data definitions, which are accessed from C++.

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/10/2009 9:42:29 AM

On 10 Jul., 11:42, Frank Buss <f...@frank-buss.de> wrote:
> Rainer Joswig wrote:
> > You should come to the Lisp meeting organized by Edi Weitz and Arthur
> > Lemmens
> > in Hamburg:http://weitz.de/eclm2009/
>
> Thanks, but my focus has shifted a bit. Currently I'm trying to learn pia=
no
> playing in my spare time :-)

Hmm, so you post here though your focus shifted? You are not
interested
in meeting Lisp people, your focus shifted, but you tell us at most
five applications
are written in Lisp? Strange.

> > I'm pretty sure several people can tell you a bit about the
> > applications
> > they are writing or have written. If you were a bit more familiar with
> > the
> > domains Common Lisp is used mostly, you would know that there
> > are thousands of applications written in Common Lisp. That you don't
> > know them does not mean they don't exist.
>
> You are right, this was a bit exaggerated by me. But the point is that
> there are millions of applications in C-like languages, so I think at lea=
st
> it is true, that there are less than 2% Lisp programmers and programs. Of
> course, this doesn't mean that C is better than Lisp. It is better, if yo=
u
> want to get a programming job, but if you are a good Lisp and a good C
> programmer, I think it is easier to implement a given problem in Lisp.

Hmm, what you say is trivially known. Everybody knows that there
are more C programmers than Lisp programmers. What is new?
2% of millions of applications can be quite a lot in absolute
numbers and does not say much about the importance and the value
of these applications to their users.

There are also more VW rabbits than Mercedes Unimogs. But what does
it say really? There are more drivers able to drive a VW rabbit?
Great, let's do some forest work with the VW rabbit.

>
> > But now Naughty Dog uses Scheme again.
>
> > =A0http://www.naughtydog.com/corporate/press/GDC%202008/AdventuresInDat=
a...
>
> I don't see that they are using it again. They write that they are planni=
ng
> to use it ("We will build DC in Scheme") and the presentation has some C+=
+
> examples, too, so looks like it will be a mix of Scheme and C++, using th=
e
> Scheme part for data definitions, which are accessed from C++.

A mix of C++ and Scheme equals zero Scheme? I don't understand your
arithmetic.
Is use of Scheme valid only if all software is written in Scheme?

This describes where and how they use Scheme and what they use else:

http://www.naughtydog.com/corporate/press/GDC%202008/UnchartedTechGDC2008.p=
df

0
Reply joswig8642 (2198) 7/10/2009 10:01:40 AM

Rainer Joswig wrote:

> Hmm, so you post here though your focus shifted? You are not
> interested
> in meeting Lisp people, your focus shifted, but you tell us at most
> five applications
> are written in Lisp? Strange.

There is nothing strange about it. I'm still interested in Lisp, but more
in piano playing :-)

> A mix of C++ and Scheme equals zero Scheme? I don't understand your
> arithmetic.

I didn't wrote that they don't use Scheme, I just added the missing
information from your post that they are using it in combination with C++.

> Is use of Scheme valid only if all software is written in Scheme?

No. I think it is a good idea to mix different languages. Each language has
its pros and cons, e.g. Scheme could be nice for scripting and representing
data and C is nice for graphic card shaders.

> This describes where and how they use Scheme and what they use else:
> 
> http://www.naughtydog.com/corporate/press/GDC%202008/UnchartedTechGDC2008.pdf

I don't see details how they used Scheme, but on page 20 they write, that
initially they used it for creating data structures, later scripting and
other things.

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/10/2009 10:20:03 AM

On 10 Jul., 12:20, Frank Buss <f...@frank-buss.de> wrote:

> Rainer Joswig wrote:
> > Hmm, so you post here though your focus shifted? You are not
> > interested
> > in meeting Lisp people, your focus shifted, but you tell us at most
> > five applications
> > are written in Lisp? Strange.
>
> There is nothing strange about it. I'm still interested in Lisp, but more
> in piano playing :-)

So you are going to be a professional piano player? Why piano?
There are many more people playing other instruments.
You can also get more music pieces for other instruments!
Isn't the guitar more popular in mainstream music?
Why not use a more modern instrument? If you use a
computer sequencer you could check your notes before playing
and that would greatly reduce the possibility of false
notes! I'd say the piano has been superseded by more modern
instruments long ago! Btw, I have written a book:

  Synthesizer for Scientists.

You should read it!

> > A mix of C++ and Scheme equals zero Scheme? I don't understand your
> > arithmetic.
>
> I didn't wrote that they don't use Scheme, I just added the missing
> information from your post that they are using it in combination with C++.
>
> > Is use of Scheme valid only if all software is written in Scheme?
>
> No. I think it is a good idea to mix different languages. Each language has
> its pros and cons, e.g. Scheme could be nice for scripting and representing
> data and C is nice for graphic card shaders.
>
> > This describes where and how they use Scheme and what they use else:
>
> >http://www.naughtydog.com/corporate/press/GDC%202008/UnchartedTechGDC...
>
> I don't see details how they used Scheme, but on page 20 they write, that
> initially they used it for creating data structures, later scripting and
> other things.

Dan Liebgold says:

We build upon this basis to create many many things
  Particle definitions
  Animation states
  Gameplay scripts
  Scripted in-gamecinematics
  Weapons tuning
  Sound and voice setup
  Overall game sequencing and control

I would say that's quite substantial...
0
Reply joswig8642 (2198) 7/10/2009 10:37:50 AM

Rainer Joswig wrote:

> So you are going to be a professional piano player?

No, it's just a hobby, like Lisp programming :-)

> Why piano?
> There are many more people playing other instruments.
> You can also get more music pieces for other instruments!
> Isn't the guitar more popular in mainstream music?
> Why not use a more modern instrument? If you use a
> computer sequencer you could check your notes before playing
> and that would greatly reduce the possibility of false
> notes! I'd say the piano has been superseded by more modern
> instruments long ago!

Nice analogy! I have an electronic piano and it has a MIDI interface for
interfacing with a PC. And there are even sequencers, where you can setup
note and velocity quantizing, but the recording looses lots of expression.
And no synthesizer can produce such a wide range of nuances like a good old
real grand piano, which I play every week at a music school.

Compared to other instruments, a piano can produce lots of different styles
of music, which is impossible with other instruments, or at least doesn't
sound as good and e.g. a guitar has much less octaves than a grand piano.

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/10/2009 10:58:44 AM

On Jul 9, 7:32=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > So what do you want from a programming language?
>
> Excellent question. I've never really tried to enumerate it before...
>
In short, the One Ring to rule them all. I've been there. The thing
is, everyone has a different idea about how the One Ring should look
and work. As a result, we either complain and annoy those who are
basically happy with the status quo and are actually writing stuff, or
we implement yet another ultimate programming language.

I'm sure you'll be happy with HLVM when it's done. However, the next
guy will look at it, say "WTF?", and implement his own personal Ring.

I think a better approach for the rest of us is to find one or more
platforms that are "good enough" (CL and Haskell both work for me) and
start coding apps and libraries.


0
Reply larryliberty (26) 7/10/2009 11:27:13 AM

On 10 Jul., 12:58, Frank Buss <f...@frank-buss.de> wrote:
> Rainer Joswig wrote:
> > So you are going to be a professional piano player?
>
> No, it's just a hobby, like Lisp programming :-)
>
> > Why piano?
> > There are many more people playing other instruments.
> > You can also get more music pieces for other instruments!
> > Isn't the guitar more popular in mainstream music?
> > Why not use a more modern instrument? If you use a
> > computer sequencer you could check your notes before playing
> > and that would greatly reduce the possibility of false
> > notes! I'd say the piano has been superseded by more modern
> > instruments long ago!
>
> Nice analogy! I have an electronic piano and it has a MIDI interface for
> interfacing with a PC. And there are even sequencers, where you can setup
> note and velocity quantizing, but the recording looses lots of expression.
> And no synthesizer can produce such a wide range of nuances like a good old
> real grand piano, which I play every week at a music school.
>
> Compared to other instruments, a piano can produce lots of different styles
> of music, which is impossible with other instruments, or at least doesn't
> sound as good and e.g. a guitar has much less octaves than a grand piano.

The market for grand pianos is tiny compared to the market for
synthesizers.
Also Google returns many more hits for "synthesizer" than for "grand
piano".
You can also see that Google trends shows less and less searches
for "grand piano". Also the best piano players have switched to more
modern instruments long ago. The only hope I would have is with a
more modern version that is not bound by the historical baggage
of old music, old fashioned piano design, and the limited amount of
sounds
it can produce.


>
> --
> Frank Buss, f...@frank-buss.dehttp://www.frank-buss.de,http://www.it4-systems.de

0
Reply joswig8642 (2198) 7/10/2009 11:28:21 AM

Rainer Joswig <joswig@lisp.de> writes:

> The market for grand pianos is tiny compared to the market for
> synthesizers.  Also Google returns many more hits for "synthesizer" than
> for "grand piano".  You can also see that Google trends shows less and
> less searches for "grand piano". Also the best piano players have
> switched to more modern instruments long ago. The only hope I would have
> is with a more modern version that is not bound by the historical baggage
> of old music, old fashioned piano design, and the limited amount of
> sounds it can produce.

:-)  But you should still add a link to your "Flying Music Consultancy"...

Nicolas
0
Reply lastname7788 (201) 7/10/2009 11:51:06 AM

Nicolas Neuss <lastname@math.uni-karlsruhe.de> writes:

> :-)  But you should still add a link to your "Flying Music Consultancy"...

nah, we get it, no need to overdo things. :)

cheers,
--m
0
Reply usenet6643 (72) 7/10/2009 12:21:24 PM

On Jul 10, 4:28=A0am, Rainer Joswig <jos...@lisp.de> wrote:
> On 10 Jul., 12:58, Frank Buss <f...@frank-buss.de> wrote:
>
>
>
>
>
> > Rainer Joswig wrote:
> > > So you are going to be a professional piano player?
>
> > No, it's just a hobby, like Lisp programming :-)
>
> > > Why piano?
> > > There are many more people playing other instruments.
> > > You can also get more music pieces for other instruments!
> > > Isn't the guitar more popular in mainstream music?
> > > Why not use a more modern instrument? If you use a
> > > computer sequencer you could check your notes before playing
> > > and that would greatly reduce the possibility of false
> > > notes! I'd say the piano has been superseded by more modern
> > > instruments long ago!
>
> > Nice analogy! I have an electronic piano and it has a MIDI interface fo=
r
> > interfacing with a PC. And there are even sequencers, where you can set=
up
> > note and velocity quantizing, but the recording looses lots of expressi=
on.
> > And no synthesizer can produce such a wide range of nuances like a good=
 old
> > real grand piano, which I play every week at a music school.
>
> > Compared to other instruments, a piano can produce lots of different st=
yles
> > of music, which is impossible with other instruments, or at least doesn=
't
> > sound as good and e.g. a guitar has much less octaves than a grand pian=
o.
>
> The market for grand pianos is tiny compared to the market for
> synthesizers.
> Also Google returns many more hits for "synthesizer" than for "grand
> piano".
> You can also see that Google trends shows less and less searches
> for "grand piano". Also the best piano players have switched to more
> modern instruments long ago. The only hope I would have is with a
> more modern version that is not bound by the historical baggage
> of old music, old fashioned piano design, and the limited amount of
> sounds
> it can produce.

Don't forget non-portability.  And have you ever played on a good
Grand Piano after playing on a nice, cheap, synthesized piano?  The
keys are hard to press, and that you have to press the keys at all is
just ludicrous - give me a good, cheap, player piano any day.

:-)

Duane

0
Reply duane8 (1151) 7/10/2009 3:52:23 PM

On Jul 10, 1:10=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > I think a better approach for the rest of us is to find one or more
> > platforms that are "good enough" (CL and Haskell both work for me) and
> > start coding apps and libraries.
>
> I think that is an extremely bad idea because you're building on sand. Th=
e
> very foundation of your applications and libraries is rotting.

What does this even mean?

>
> Microsoft were right on the money when they built .NET as a rock solid
> foundation for everyone to use going forward and they are right to put a
> huge amount of effort into migrating as much old code to run on top of .N=
ET
> as possible. They are so far ahead of Linux now that it is just ridiculou=
s.
>
And for all that the .NET languages are so far inadequate to meet your
needs that you feel compelled to create yet another programming
environment.

> For a start, you're advocating using at least two separate and
> uninteroperable garbage collectors in CL and Haskell. That is obviously a
> really bad idea, not to mention that no implementations of either CL or
> Haskell have GCs comparable to those found in the JVM and .NET.
>

Actually, I'm only advocating picking something that works reasonably
well and getting on with it. I use either CL or Haskell according to
the task.

Also, I don't think you really got the point I was trying to make
earlier. So, let's ask this question: Don't you think the creators of
Ruby, Arc, Clojure, etc., all thought they were creating the ultimate
programming environment?


0
Reply larryliberty (26) 7/10/2009 4:19:43 PM

Vassil Nikolov wrote:
> On Fri, 10 Jul 2009 00:32:57 +0100, Jon Harrop <jon@ffconsultancy.com>
> said:
>> ...
>> unconventional operators (e.g. ** for power ...)
> 
>   That is an at-least-55-year-old convention.  How much more
>   conventional can it get?

Superscript is more conventional.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 4:26:14 PM

fft1976 <fft1976@gmail.com> wrote:

> > > So what do you want from a programming language?
> >
> > Excellent question. I've never really tried to enumerate it
> > before...
>
> (snip)
>
> This "being functional" is an unhealthy obsession. 3/4 of the time
> imperative idioms are more convenient, and 1/4 of the time functional
> ones are more convenient.

Fortunately that's just your opinion and not the reality.  Even
Microsoft has found the value in functional programming.  See F#.  It's
scheduled to be packaged with Visual Studio in 2010, AFAIK.  Also many
imperative languages are employing more and more functional concepts.


> But because most popular languages are imperative, people are whining
> about those 1/4 cases and some disturbed individuals even think
> languages should be pure-functional.

What's wrong with purely functional languages?


> What I want is a safe (or has an option to be safe), fast mostly
> imperative language that doesn't suck.

If you want safety, go for functional programming.  About speed, most
decent functional languages aren't considerably slower than C, but given
that you save a lot of development time, you'll get your result much
faster.

Also purely functional languages (e.g. Haskell, Clean) and languages
with immutable data (e.g. F#) allow clean and concise algorithm
implementations, which are still just as fast as imperative variants
with explicit reference/memory handling.  Finally with these two classes
of languages and additionally Erlang you get concurrency and parallelity
almost for free.  Multithreaded programming is a PITA in all imperative
languages.


> C++ (if you are very good and very careful), Java and OCaml are
> decent, but not quite what I want. Maybe D and Ada, although I don't
> know about those.

Just in case you didn't notice, OCaml is a functional language.
However, nobody is "very good" and "very careful".  C++ leaves too many
spots open for making mistakes.  D is much better at that, if you insist
on imperative programming.

All in all you're just showing that you don't have a clue about
functional programming.  Before making such unfounded claims, you'd
better try a functional language for more than 15 minutes.  If you still
think that functional programming sucks, you should provide reasons to
support your claims.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/10/2009 4:40:49 PM

Frank Buss wrote:
> Jon Harrop wrote:
>> Libraries: Nothing on Linux comes close to Windows Presentation
>> Foundation for robustly-deployable hardware accelerated UIs
> 
> Do you know Qt and wxWidgets?

Yes, of course. Neither even attempt to provide hardware accelerated GUIs as
WPF does.

> Both libraries are really nice

They could barely be any worse. Even their own demo programs segfault
because the foundations they are built upon are rotten to the core.

Look at the use of first-class lexical closures in WPF, for example. Suffice
to say, C++ is nowhere near competitive in this respect.

> and the GUI editor for Qt is as complete as for WPF,

Nowhere near. WPF's GUI editor generates high-level safe interoperable code
than runs on .NET. I can call it directly from F# to generate binary
executables that millions of people can run directly.

Qt is a generation behind, generating code in a proprietary dialect of C++
that could barely be less safe or interoperable. I cannot even use Qt
directly from OCaml and, if I could, any compiled binaries would be brittle
with respect to the exact versions on all libraries on my machine so they
would segfault on the vast majority of other machines. So the only
practical option is to distribute source code and ask users to recompile it
or distro maintainers to create custom packages for it. That throws up
barriers to commercial software on Linux. Moreover, if you even try to
discuss making Linux more commerce friendly, you get trampled by millions
of freeloaders who want to impose "freedom" upon people by taking that
choice away from them. Hence the quality of software on Linux is already
bad and is getting worse.

And I suppose I would be expected to go back to battling with bugs in the
g++ toolchain? No thanks. I dropped that crappy language and implementation
years ago for good reasons and have no intention of going backwards.

> but if you are using layout 
> managers, you can't do bugs like this one with the buttons in the bottom
> area, found in Microsoft Visual Studio 2008:
> 
> http://www.frank-buss.de/tmp/gui-bug.jpg

Firstly, that software isn't even using WPF. Secondly, KDE is riddled with
similar rendering bugs.

> I don't know if Microsoft practices "eat your own dogfood" and if they are
> using WPF, but this is not a good publicity for their framework.

WPF is in VS 2010.

> wxWidgets has some nice GUI editors, too and it uses the native controls
> of the operating system, so I assume they are hardware accelerated, but 
> why is this important for a GUI, if you just want to display some text and
> edit fields and not realtime 3D animation?

Are you seriously asking why someone developing a *graphical* user interface
might be interested in decent graphics?

> Qt is available as LGPL, now that Nokia bought Trolltech for Windows (last
> year it was available for Windows as commercial, only). wxWidget is
> available for Win32, Mac OS X, GTK+, X11, Motif, WinCE, and more, and has
> a LPGL-like licence.

Sure. Neither are remotely close to providing what I was asking for.

GUI libraries should be written in safe languages and they should use a
highly-reliable subset of the low-level rendering libraries for hardware
accelerated graphics. Qt and wxWidgets are both written in unsafe low-level
languages and neither make any attempt to hardware accelerate the contents
of windows. You can make completely uninteroperable use of the whole of
OpenGL but it is entirely unsafe, e.g. you can screw up the rendering
context for the next Window and cause widespread corruption.

GUI libraries should be interoperable so that many programming languages can
reap the benefits of a single mature GUI framework. Qt is written in a
proprietary dialect of C++ which is extremely difficult to interoperate
with. This essentially requires some kind of common language run-time but,
of course, Linux doesn't have any that support basic features like TCO.

GUI libraries should be written in high-level languages. The idea of trying
to write a decent framework without garbage collection is now laughable.

Finally, writing a GUI library is actually comparatively easy. The hard part
is building the foundation upon which everything is built, i.e. the safe
interoperable VM. Linux desperately needs such a thing but, so far, we're
stuck with the JVM and Mono.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 5:04:49 PM

Don Geddis wrote:
> So, why do you post on this newsgroup, c.l.l?  It's clearly for people wh=
o
> are interested in Lisp.  If you're not, why are you here?

See:

=E2=80=A2 Why do I Rant In comp.lang.lisp?
  http://xahlee.org/UnixResource_dir/writ/why_comp_lang_lisp.html

In the past, i wouldn't have answered your idiotic question, because
it is off topic and all. But now i do, taking it as a chance to speak
for myself. Why? See:

=E2=80=A2 How Shall I Respond?
  http://xahlee.org/Netiquette_dir/how_shall_i_respond.html

On retrospect of the article =E2=80=9CWhy do I Rant In comp.lang.lisp?=E2=
=80=9D, i ask
myself whether i have achieved something about creating a book length
collection of my ideas and opinions. I must say yes i have. For
example, especially in the past few years, usually when i argue with
the tech geekers online, i can usually pull out a collection of some 5
or 10 essays of my opinions or tech expositions on a some particular
argued topic. For example of this, recent debate about lisp1 vs lisp2
in this very thread, i pulled out 10 essays about jargons:

=E2=80=A2 The Importance of Terminology's Quality In Computer Languages
  http://xahlee.org/UnixResource_dir/writ/naming_functions.html

=E2=80=A2 Jargons of Info Tech Industry
  http://xahlee.org/UnixResource_dir/writ/jargons.html

=E2=80=A2 Why You should Not Use The Jargon Lisp1 and Lisp2
  http://xahlee.org/emacs/lisp1_vs_lisp2.html

=E2=80=A2 The Term Currying In Computer Science
  http://xahlee.org/UnixResource_dir/writ/currying.html

=E2=80=A2 What Is Closure In A Programing Language
  http://xahlee.org/UnixResource_dir/writ/closure.html

=E2=80=A2 What are OOP's Jargons and Complexities
  http://xahlee.org/Periodic_dosage_dir/t2/oop.html

=E2=80=A2 Interface in Java
  http://xahlee.org/java-a-day/interface.html

=E2=80=A2 Math Terminology and Naming of Things
  http://xahlee.org/cmaci/notation/math_namings.html

=E2=80=A2 Politics and the English Language
  http://xahlee.org/p/george_orwell_english.html

btw, your idiotic reply:
> So, why do you post on this newsgroup, c.l.l?  It's clearly for people wh=
o
> are interested in Lisp.  If you're not, why are you here?

is actually wrong, and is a common response to me in the past 10
years. People say that to me on Perl, Python groups, as well. I guess
i could spend few hours now and write another essay focused on
expounding this issue... and creating a addition to my essay
collection. Not sure i feel like that now though. But to quip, why are
YOU not interested in lisp?? if not, why r u here?? arn't u trolling?

Thanks for your troll, cause, without trolls like u, i wouldn't have
the chance, the spur, to have created my essays in the past decade.

  Xah
=E2=88=91 http://xahlee.org/

=E2=98=84
0
Reply xahlee (818) 7/10/2009 5:05:23 PM

Larry Coleman wrote:
> I think a better approach for the rest of us is to find one or more
> platforms that are "good enough" (CL and Haskell both work for me) and
> start coding apps and libraries.

I think that is an extremely bad idea because you're building on sand. The
very foundation of your applications and libraries is rotting.

Microsoft were right on the money when they built .NET as a rock solid
foundation for everyone to use going forward and they are right to put a
huge amount of effort into migrating as much old code to run on top of .NET
as possible. They are so far ahead of Linux now that it is just ridiculous.

For a start, you're advocating using at least two separate and
uninteroperable garbage collectors in CL and Haskell. That is obviously a
really bad idea, not to mention that no implementations of either CL or
Haskell have GCs comparable to those found in the JVM and .NET.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 5:10:16 PM

On Jul 10, 6:40=A0pm, Ertugrul S=F6ylemez <e...@ertes.de> wrote:
> Fortunately that's just your opinion and not the reality. =A0Even
> Microsoft has found the value in functional programming. =A0See F#. =A0It=
's
> scheduled to be packaged with Visual Studio in 2010, AFAIK. =A0Also many
> imperative languages are employing more and more functional concepts.

F# is not purely functional.

> > But because most popular languages are imperative, people are whining
> > about those 1/4 cases and some disturbed individuals even think
> > languages should be pure-functional.
>
> What's wrong with purely functional languages?
>
> > What I want is a safe (or has an option to be safe), fast mostly
> > imperative language that doesn't suck.
>
> If you want safety, go for functional programming.

Why?
Type safety is orthogonal to the functional/imperative distinction.

> =A0About speed, most
> decent functional languages aren't considerably slower than C, but given
> that you save a lot of development time, you'll get your result much
> faster.

However, if I understand correctly, purely functional languages
typically have performance problems.

> Also purely functional languages (e.g. Haskell, Clean) and languages
> with immutable data (e.g. F#) allow clean and concise algorithm
> implementations, which are still just as fast as imperative variants
> with explicit reference/memory handling.

This makes no sense, since you can always use mutable variables as if
they were immutable.

What makes functional languages more coincise is the availability of
first-class procedures.
Lazy evaluation can also improve expressivity, at the cost of
performance problems.

> =A0Finally with these two classes
> of languages and additionally Erlang you get concurrency and parallelity
> almost for free. =A0Multithreaded programming is a PITA in all imperative
> languages.

Again, these issues are orthogonal. Erlang's message passing model of
concurrency can be also used in imperative languages.

> > C++ (if you are very good and very careful), Java and OCaml are
> > decent, but not quite what I want. Maybe D and Ada, although I don't
> > know about those.
>
> Just in case you didn't notice, OCaml is a functional language.

But it is not pure.

> However, nobody is "very good" and "very careful". =A0C++ leaves too many
> spots open for making mistakes. =A0D is much better at that, if you insis=
t
> on imperative programming.
>
> All in all you're just showing that you don't have a clue about
> functional programming. =A0Before making such unfounded claims, you'd
> better try a functional language for more than 15 minutes. =A0If you stil=
l
> think that functional programming sucks, you should provide reasons to
> support your claims.

He didn't say that functional programming sucks, he said that the
functional paradigm is useful 25% of times.
0
Reply vend82 (230) 7/10/2009 5:26:15 PM

"fft1976" <fft1976@gmail.com> wrote in message 
news:7218d55d-7ae0-4a2e-b83c-35fbdbcc6330@h8g2000yqm.googlegroups.com...
> On Jul 9, 4:32 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Larry Coleman wrote:
>> > So what do you want from a programming language?
>>
>> Excellent question. I've never really tried to enumerate it before...
>
> (snip)
>
> This "being functional" is an unhealthy obsession. 3/4 of the time
> imperative idioms are more convenient, and 1/4 of the time functional
> ones are more convenient.
>
> But because most popular languages are imperative, people are whining
> about those 1/4 cases and some disturbed individuals even think
> languages should be pure-functional.
>
> What I want is a safe (or has an option to be safe), fast mostly
> imperative language that doesn't suck.
>
> C++ (if you are very good and very careful), Java and OCaml are
> decent, but not quite what I want. Maybe D and Ada, although I don't
> know about those.

How about C# 3? It's mostly imperative, but it has LINQ (which is 
functional) and the closure syntax is very short and un-messy. 

0
Reply harold.aptroot (91) 7/10/2009 6:00:35 PM

On 2009-07-10 12:40:49 -0400, Ertugrul S�ylemez <es@ertes.de> said:

> What's wrong with purely functional languages?

The "purely" part. Some solutions are naturally expressed in a pure 
functional manner. Others are not. The programmer should have a choice.

Moreover, there's abundant linguistic and cognitive scientific evidence 
that human beings naturally conceptualize the world in terms of 
stateful entities and their mutation, not functionally, so imperative 
languages fit our natural cognitive models better. This suggests that 
DSLs will often include an imperative component in their surface syntax 
at the very least.


-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/10/2009 6:03:29 PM

Jon Harrop wrote:

> They could barely be any worse. Even their own demo programs segfault
> because the foundations they are built upon are rotten to the core.

Are we talking about the same library? Qt is a mature library, KDE and lots
of programs are based on it, QTopia and QTE works on lots of embedded
devices. I've never seen a segfault in one of the Qt demo programs. I've
tried version 4.4 on a x86 Linux box and the QTE version on an ARM embedded
device, for which I've developed my own graphics driver, which translates
the Qt calls to accelerated calls to an attached graphics chip. Qt has a
nice architecture to make such things very easy.

> Look at the use of first-class lexical closures in WPF, for example. Suffice
> to say, C++ is nowhere near competitive in this respect.

Yes, this could be a nice feature.

> Nowhere near. WPF's GUI editor generates high-level safe interoperable code
> than runs on .NET. I can call it directly from F# to generate binary
> executables that millions of people can run directly.
> 
> Qt is a generation behind, generating code in a proprietary dialect of C++
> that could barely be less safe or interoperable. 

This is only half of the truth: You can generate C++ code, but for a
commercial project e.g. I save the GUI forms as XML, which are loaded by
JavaScript, which is integrated in Qt and which has access to all GUI
elements. The GC and prototype based programming style of JavaScript is
very nice for GUI programming, e.g. you can use anonymous functions as
button handlers with a very simple syntax.

> I cannot even use Qt
> directly from OCaml and, if I could, any compiled binaries would be brittle
> with respect to the exact versions on all libraries on my machine so they
> would segfault on the vast majority of other machines. So the only
> practical option is to distribute source code and ask users to recompile it
> or distro maintainers to create custom packages for it. That throws up
> barriers to commercial software on Linux.

This is wrong. There are many way how to use Qt: On Linux there is no
problem with different versions of libraries, because it has a descent
version managment for shared libraries and you link your programs to the
right version, which you can deliver with your application, if not already
installed on the system. To avoid any problems, you can even link it
statically to your application.

I've just installed
http://get.qtsoftware.com/qtsdk/qt-sdk-win-opensource-2009.03.exe 
Included in this release was even the compiler (based on MinGW) and with Qt
Creator an IDE you don't need any other program to start programming. There
is a demo, which just works, no "brittle" problems at all.

> And I suppose I would be expected to go back to battling with bugs in the
> g++ toolchain? No thanks. I dropped that crappy language and implementation
> years ago for good reasons and have no intention of going backwards.

Does WPF even exists for Linux? On Windows Qt works with Visual Studio,
which has not a perfect C++ compiler, but still good quality.

>> wxWidgets has some nice GUI editors, too and it uses the native controls
>> of the operating system, so I assume they are hardware accelerated, but 
>> why is this important for a GUI, if you just want to display some text and
>> edit fields and not realtime 3D animation?
> 
> Are you seriously asking why someone developing a *graphical* user interface
> might be interested in decent graphics?

I was thinking of warehouse applications, databases etc., but you are right
that you need accelerated graphics for multimedia applications etc. Thanks
Trolltech that they support it :-)

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/10/2009 6:15:42 PM

Ertugrul Söylemez wrote:
> fft1976 <fft1976@gmail.com> wrote:
>> But because most popular languages are imperative, people are whining
>> about those 1/4 cases and some disturbed individuals even think
>> languages should be pure-functional.
> 
> What's wrong with purely functional languages?

.. Unpredictable performance.

.. Unreliable.

.. Uninteroperable.

>> What I want is a safe (or has an option to be safe), fast mostly
>> imperative language that doesn't suck.
> 
> If you want safety, go for functional programming.

If you want to interoperate with code written in other languages then
functional languages like OCaml and Haskell are *less* safe than the JVM
and CLR because their FFIs are comparatively poorly designed and poorly
implemented.

> About speed, most decent functional languages aren't considerably slower
> than C, 

That assertion is uselessly subjective. What are "decent" functional
languages? How much is "considerably" slower? Why are you comparing with C?
Are you assuming GCC and not Intel C++ (which often generates code that is
several times faster)?

The fastest BWT implementation written in Haskell, after weeks of
optimization by several experts, remained over 200x slower than C++:

http://www.mail-archive.com/haskell-cafe%40haskell.org/msg25645.html

So either Haskell is not "decent" or 200x slower is "not considerably
slower".

> but given that you save a lot of development time, you'll get your result
> much faster.

Not if your "result" is efficient code, which is often the case for
professional developers because their end users demand speed.

> Also purely functional languages (e.g. Haskell, Clean) and languages
> with immutable data (e.g. F#) allow clean and concise algorithm
> implementations, which are still just as fast as imperative variants
> with explicit reference/memory handling.  Finally with these two classes
> of languages and additionally Erlang you get concurrency and parallelity
> almost for free.

GHC's stop-the-world GC does not scale so Haskell programmers obviously do
not get "parallelism almost for free".

> Multithreaded programming is a PITA in all imperative languages.

Cilk makes parallelism easy.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 6:29:54 PM

Vend <vend82@virgilio.it> wrote:

> > Fortunately that's just your opinion and not the reality. =C2=A0Even
> > Microsoft has found the value in functional programming. =C2=A0See
> > F#. =C2=A0It's scheduled to be packaged with Visual Studio in 2010,
> > AFAIK. =C2=A0Also many imperative languages are employing more and more
> > functional concepts.
>
> F# is not purely functional.

So...?


> > > What I want is a safe (or has an option to be safe), fast mostly
> > > imperative language that doesn't suck.
> >
> > If you want safety, go for functional programming.
>
> Why?
> Type safety is orthogonal to the functional/imperative distinction.

Type safety is one kind of safety.  The functional paradigm gives you
other types of safety, too, which doesn't require additional language
constructs like 'foreach'.


> > =C2=A0About speed, most decent functional languages aren't considerably
> > slower than C, but given that you save a lot of development time,
> > you'll get your result much faster.
>
> However, if I understand correctly, purely functional languages
> typically have performance problems.

That statement wasn't restricted to purely functional languages, but
despite Dr. Harrop's usual noise purely functional languages perform
quite well.


> > Also purely functional languages (e.g. Haskell, Clean) and languages
> > with immutable data (e.g. F#) allow clean and concise algorithm
> > implementations, which are still just as fast as imperative variants
> > with explicit reference/memory handling.
>
> This makes no sense, since you can always use mutable variables as if
> they were immutable.

You cannot in the same convenient way.  With immutable data you can make
a function take a tree and return a slightly modified tree without much
programming effort.


> What makes functional languages more coincise is the availability of
> first-class procedures.

Modern imperative languages have that as well.  Functional programming
is a paradigm, not a tool.


> Lazy evaluation can also improve expressivity, at the cost of
> performance problems.

Lazy evaluation is a semantic property.  What it compiles to is a
different question.  Particularly Haskell as the outrider in non-strict
semantics does quite well at that (with GHC).


> > =C2=A0Finally with these two classes of languages and additionally Erla=
ng
> > you get concurrency and parallelity almost for free. =C2=A0Multithreaded
> > programming is a PITA in all imperative languages.
>
> Again, these issues are orthogonal. Erlang's message passing model of
> concurrency can be also used in imperative languages.

Erlang is inherently thread-safe.  The other languages I mentioned get
that property partly through immutable data and partly through excellent
synchronization constructs.


> > > C++ (if you are very good and very careful), Java and OCaml are
> > > decent, but not quite what I want. Maybe D and Ada, although I
> > > don't know about those.
> >
> > Just in case you didn't notice, OCaml is a functional language.
>
> But it is not pure.

So...?  The OP obviously doesn't like functional programming.  That's my
point.


> > However, nobody is "very good" and "very careful". =C2=A0C++ leaves too
> > many spots open for making mistakes. =C2=A0D is much better at that, if
> > you insist on imperative programming.
> >
> > All in all you're just showing that you don't have a clue about
> > functional programming. =C2=A0Before making such unfounded claims, you'd
> > better try a functional language for more than 15 minutes. =C2=A0If you
> > still think that functional programming sucks, you should provide
> > reasons to support your claims.
>
> He didn't say that functional programming sucks, he said that the
> functional paradigm is useful 25% of times.

Yes, and he didn't support that statement by anything.


Greets,
Ertugrul.


--=20
nightmare =3D unsafePerformIO (getWrongWife >>=3D sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/10/2009 6:42:52 PM

Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> wrote:

> > What's wrong with purely functional languages?
>
> The "purely" part. Some solutions are naturally expressed in a pure
> functional manner. Others are not. The programmer should have a
> choice.

They have a choice.  A purely functional language has a theoretical
property, which is very useful.  That doesn't mean you can't use the
things you're used to.  You just don't -- usually.


> Moreover, there's abundant linguistic and cognitive scientific
> evidence that human beings naturally conceptualize the world in terms
> of stateful entities and their mutation, not functionally, so
> imperative languages fit our natural cognitive models better. This
> suggests that DSLs will often include an imperative component in their
> surface syntax at the very least.

And we all know that humans are far from perfect.  They make mistakes
all the time just because of that cognitive property.  Safety is all
about restricting this or finding alternatives.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/10/2009 6:51:38 PM

>> What's wrong with purely functional languages?
>
> The "purely" part. Some solutions are naturally expressed in a pure 
> functional manner. Others are not. The programmer should have a choice.

Uh, in Haskell you absolutely do have a choice.  Haskell gives the programmer
access to all the non-functional things you want: mutable cells, mutable arrays,
foreign functions, IO, etc.  You just have to use monads to get to it all.  You
can take any imperative algorithm you like and translate it into Haskell in a
totally straightforward way.  


        --larry





0
Reply larry4779 (10) 7/10/2009 6:55:48 PM

Jon Harrop <jon@ffconsultancy.com> wrote:

> > What's wrong with purely functional languages?
>
> . Unpredictable performance.

Wrong.


> . Unreliable.

Wrong (although right to some extent on PPC).


> . Uninteroperable.

Right.  That's something that could use some improvement.


> > About speed, most decent functional languages aren't considerably
> > slower than C,
>
> That assertion is uselessly subjective. What are "decent" functional
> languages? How much is "considerably" slower? Why are you comparing
> with C?  Are you assuming GCC and not Intel C++ (which often generates
> code that is several times faster)?
>
> The fastest BWT implementation written in Haskell, after weeks of
> optimization by several experts, remained over 200x slower than C++:
>
> http://www.mail-archive.com/haskell-cafe%40haskell.org/msg25645.html
>
> So either Haskell is not "decent" or 200x slower is "not considerably
> slower".

Hmm.  This one took me about 10 minutes:

  bwt :: B.ByteString -> B.ByteString
  bwt str =
    let sorted = map fst . sortBy (compare `on` snd) $ zip [0, 1..] (B.unpack str)
        slen   = B.length str
    in B.pack . map (\i -> B.index str ((i-1) `mod` slen)) $ sorted

It's not optimal, because it uses list sorting.  Replace it by an
in-place sort and you're set.


> GHC's stop-the-world GC does not scale so Haskell programmers
> obviously do not get "parallelism almost for free".

Right.  It's not that it makes such a big difference anyway, but it
could be improved a lot.  When using explicit threading in Haskell I
usually get c*n*100% of the performance of a single thread, where c is
some constant between 0.8 and 0.9 and n is the number of CPUs and
threads.  Unfortunately this is not true for implicit parallelism using
strategies, but I don't believe that this can be improved a lot.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/10/2009 7:28:40 PM

Vend wrote:
> Why?
> Type safety is orthogonal to the functional/imperative distinction.

Only in theory. In practice, functional languages (OCaml, Haskell) offer far
more expressive type systems than any available safe imperative language
implementation (Java, C#).

>> Also purely functional languages (e.g. Haskell, Clean) and languages
>> with immutable data (e.g. F#) allow clean and concise algorithm
>> implementations, which are still just as fast as imperative variants
>> with explicit reference/memory handling.
> 
> This makes no sense, since you can always use mutable variables as if
> they were immutable.

That does not recover the properties of purely functional data structures.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 7:35:06 PM

Harold Aptroot wrote:
> "fft1976" <fft1976@gmail.com> wrote in message
> news:7218d55d-7ae0-4a2e-b83c-35fbdbcc6330@h8g2000yqm.googlegroups.com...
>> C++ (if you are very good and very careful), Java and OCaml are
>> decent, but not quite what I want. Maybe D and Ada, although I don't
>> know about those.
> 
> How about C# 3? It's mostly imperative, but it has LINQ (which is
> functional) and the closure syntax is very short and un-messy.

Lack of TCO and lack of type inference are major problems with C# 3 in the
context of FP. Better to use F#...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 7:38:44 PM

On Jul 10, 6:40=A0pm, Ertugrul S=F6ylemez <e...@ertes.de> wrote:
> fft1976 <fft1...@gmail.com> wrote:

> > But because most popular languages are imperative, people are whining
> > about those 1/4 cases and some disturbed individuals even think
> > languages should be pure-functional.
>
> What's wrong with purely functional languages?
They suck when the problem is not purely functional.

Slobodan
0
Reply slobodan.blazeski (1459) 7/10/2009 7:47:41 PM

On Jul 10, 12:19=A0pm, Larry Coleman <larrylibe...@yahoo.com> wrote:
> On Jul 10, 1:10=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>
> > Larry Coleman wrote:
> > > I think a better approach for the rest of us is to find one or more
> > > platforms that are "good enough" (CL and Haskell both work for me) an=
d
> > > start coding apps and libraries.
>
> > I think that is an extremely bad idea because you're building on sand. =
The
> > very foundation of your applications and libraries is rotting.
>
> What does this even mean?
>
I should clarify this, as it implies that your statement about
building on sand was meaningless. What I meant to imply was that your
statement was content-free.

Also, in relation to my earlier point, a future Dr. Harrop will say
exactly the same thing about HLVM (that using it is like building on
sand and a rotting foundation).
0
Reply larryliberty (26) 7/10/2009 7:56:10 PM

On 2009-07-10 14:55:48 -0400, Larry D'Anna <larry@elder-gods.org> said:

> You just have to use monads to get to it all.  You
> can take any imperative algorithm you like and translate it into Haskell in a
> totally straightforward way.

monads. straightforward. <= contradiction in terms


-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/10/2009 8:12:08 PM

On 2009-07-10 14:51:38 -0400, Ertugrul S�ylemez <es@ertes.de> said:

> And we all know that humans are far from perfect.  They make mistakes
> all the time just because of that cognitive property.  Safety is all
> about restricting this or finding alternatives.

And expressiveness is all about *not* restricting the ability to write 
the solution in the language of the problem domain just because of some 
misplaced notion of "safety."


-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/10/2009 8:12:52 PM

>> You just have to use monads to get to it all.  You
>> can take any imperative algorithm you like and translate it into Haskell in a
>> totally straightforward way.
>
> monads. straightforward. <= contradiction in terms

They're a bit difficult to learn, but once you understand them they're not hard
to use.


   --larry

0
Reply larry4779 (10) 7/10/2009 9:09:41 PM

["Followup-To:" header set to comp.lang.lisp.]
On 2009-07-10, Jon Harrop <jon@ffconsultancy.com> wrote:
> Here is a trivial counter example: mutate an element in an array in O(1).

easy.

http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html


        --larry

0
Reply larry4779 (10) 7/10/2009 9:13:24 PM

Ertugrul Söylemez wrote:
> Jon Harrop <jon@ffconsultancy.com> wrote:
>> > What's wrong with purely functional languages?
>>
>> . Unpredictable performance.
> 
> Wrong.

There is overwhelming evidence to the contrary. Indeed, you provide more
below...

>> So either Haskell is not "decent" or 200x slower is "not considerably
>> slower".
> 
> Hmm.  This one took me about 10 minutes:
> 
>   bwt :: B.ByteString -> B.ByteString
>   bwt str =
>     let sorted = map fst . sortBy (compare `on` snd) $ zip [0, 1..]
>     (B.unpack str)
>         slen   = B.length str
>     in B.pack . map (\i -> B.index str ((i-1) `mod` slen)) $ sorted

Your incomplete implementation is over 100x slower than bzip2. Moreover,
your Haskell runs out of memory when trying to compress only 8Mb.

The poor performance of your Haskell code is a direct consequence of
Haskell's unpredictability. Obviously you failed to predict how bad your
code was or you would not have posted an example that contradicts your own
assertions.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 10:05:21 PM

Larry D'Anna wrote:
>>> What's wrong with purely functional languages?
>>
>> The "purely" part. Some solutions are naturally expressed in a pure
>> functional manner. Others are not. The programmer should have a choice.
> 
> Uh, in Haskell you absolutely do have a choice.  Haskell gives the
> programmer access to all the non-functional things you want: mutable
> cells, mutable arrays,
> foreign functions, IO, etc.  You just have to use monads to get to it all.
>  You can take any imperative algorithm you like and translate it into
> Haskell in a totally straightforward way.

Here is a trivial counter example:

http://flyingfrogblog.blogspot.com/2009/04/f-vs-ocaml-vs-haskell-hash-table.html

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 10:08:30 PM

Ertugrul Söylemez wrote:
> Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com>
> wrote:
>> > What's wrong with purely functional languages?
>>
>> The "purely" part. Some solutions are naturally expressed in a pure
>> functional manner. Others are not. The programmer should have a
>> choice.
> 
> They have a choice.  A purely functional language has a theoretical
> property, which is very useful.  That doesn't mean you can't use the
> things you're used to.

Here is a trivial counter example: mutate an element in an array in O(1).

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 10:09:50 PM

On 2009-07-10 17:09:41 -0400, Larry D'Anna <larry@elder-gods.org> said:

> They're a bit difficult to learn, but once you understand them they're not hard
> to use.

The point here is that it is completely unnecessary cognitive overhead. 
If, semantically, I mean to do mutation of state, I should be able to 
just mutate state in a direct fashion, not have to use a state monad.

Having said that, it may (or may not) be a desireable to *implement* a 
syntax for mutation in terms of monads, but at the level of surface 
syntax, it should just look like ordinary mutation.

-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/10/2009 10:43:10 PM

Larry D'Anna wrote:
> ["Followup-To:" header set to comp.lang.lisp.]
> On 2009-07-10, Jon Harrop <jon@ffconsultancy.com> wrote:
>> Here is a trivial counter example: mutate an element in an array in O(1).
> 
> easy.
> 
> http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html

That is O(n) with GHC.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/10/2009 11:49:58 PM

Raffael Cavallaro wrote:
> On 2009-07-10 17:09:41 -0400, Larry D'Anna <larry@elder-gods.org> said:
>> They're a bit difficult to learn, but once you understand them they're
>> not hard to use.
> 
> The point here is that it is completely unnecessary cognitive overhead.

All HLL features are "unnecessary cognitive overhead".

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 12:05:50 AM

Larry D'Anna wrote:
>>> You just have to use monads to get to it all.  You
>>> can take any imperative algorithm you like and translate it into Haskell
>>> in a totally straightforward way.
>>
>> monads. straightforward. <= contradiction in terms
> 
> They're a bit difficult to learn, but once you understand them they're not
> hard to use.

But do the benefits outweigh the costs?

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 12:06:30 AM

Don Geddis wrote:
> Xah Lee <xahlee@gmail.com> wrote on Thu, 9 Jul 2009 :
>> In my opinion:
>> lisp = useless old shit.
> 
> So, why do you post on this newsgroup, c.l.l?  It's clearly for people who
> are interested in Lisp.  If you're not, why are you here?

Is c.l.lisp only for pro-Lisp misinformation?

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 12:46:56 AM

A quick analysis so that we can better understand the question  'what
is trolling?'

On Jul 10, 6:05=A0pm,  wrote:
> Ertugrul S=F6ylemez wrote:
> >  wrote:
> >> > What's wrong with purely functional languages?
>
> >> . Unpredictable performance.
>
> > Wrong.
>
> There is overwhelming evidence to the contrary. Indeed, you provide more
> below...
>
> >> So either Haskell is not "decent" or 200x slower is "not considerably
> >> slower".
>
You see here, the wiley troll makes a claim of comparison as if it is
fact. 'Haskell is 200x slower' than ...? he doesn't specify what it is
200x slower than.

> > Hmm. =A0This one took me about 10 minutes:
>
> > =A0 bwt :: B.ByteString -> B.ByteString
> > =A0 bwt str =3D
> > =A0 =A0 let sorted =3D map fst . sortBy (compare `on` snd) $ zip [0, 1.=
..]
> > =A0 =A0 (B.unpack str)
> > =A0 =A0 =A0 =A0 slen =A0 =3D B.length str
> > =A0 =A0 in B.pack . map (\i -> B.index str ((i-1) `mod` slen)) $ sorted
>

The trolled posts something to prove that his language is productive.

> Your incomplete implementation is over 100x slower than bzip2. Moreover,
> your Haskell runs out of memory when trying to compress only 8Mb.
>

The troll cleverly compares the 6 line haskell implementation to an
industry quality implementation of zip compression, specifically well
known for its speed.
The source of which being nearly 1 megabyte of information compressed.
We should note that it is only 100x slower than the high quality
implementation, while the claim was that haskell would be 200x
slower...

> The poor performance of your Haskell code is a direct consequence of
> Haskell's unpredictability. Obviously you failed to predict how bad your
> code was or you would not have posted an example that contradicts your ow=
n
> assertions.

He omits the fact that the poor performance is a result of not
comparing apples to apples in any sort of reasonable manner. He also
omits the fact that the author admited that it wasn't the highest
quality implementation of zip compression.

Here's to you Doctor Harrop, a fine specimen of the Trollish race, now
please get back under your bridge.
0
Reply anonymous.c.lisper (176) 7/11/2009 12:49:10 AM

Larry Coleman wrote:
> On Jul 10, 1:10 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Larry Coleman wrote:
>> > I think a better approach for the rest of us is to find one or more
>> > platforms that are "good enough" (CL and Haskell both work for me) and
>> > start coding apps and libraries.
>>
>> I think that is an extremely bad idea because you're building on sand.
>> The very foundation of your applications and libraries is rotting.
> 
> What does this even mean?

No attempt is being made to factor out the enormous amount of commonality
between those code bases (e.g. SBCL and GHC). For example, the garbage
collectors and the foreign function interfaces.

Hence Linux has a dozen different uninteroperable functional language
implementations each with completely separate GC implementations, none of
which are up to date with respect to important functionality like
concurrent collection.

>> Microsoft were right on the money when they built .NET as a rock solid
>> foundation for everyone to use going forward and they are right to put a
>> huge amount of effort into migrating as much old code to run on top of
>> .NET as possible. They are so far ahead of Linux now that it is just
>> ridiculous.
>
> And for all that the .NET languages are so far inadequate to meet your
> needs that you feel compelled to create yet another programming
> environment.

I was talking about the VM (CLR) and framework (e.g. WPF) and not the
languages. I am creating a new VM on Linux because Linux does not have a
suitable VM and not because Windows-only languages are inadequate.

>> For a start, you're advocating using at least two separate and
>> uninteroperable garbage collectors in CL and Haskell. That is obviously a
>> really bad idea, not to mention that no implementations of either CL or
>> Haskell have GCs comparable to those found in the JVM and .NET.
> 
> Actually, I'm only advocating picking something that works reasonably
> well and getting on with it. I use either CL or Haskell according to
> the task.

Sure.

> Also, I don't think you really got the point I was trying to make
> earlier. So, let's ask this question: Don't you think the creators of
> Ruby, Arc, Clojure, etc., all thought they were creating the ultimate
> programming environment?

This discussion has never been about creating the ultimate programming
environment. I am advocating factoring out the commonality between today's
language implementations so that we can build upon a shared VM in the
future in order to develop better language implementations more easily.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 1:04:19 AM

Frank Buss wrote:
> KDE and lots of programs are based on it,

We experience dozens of segfaults from KDE apps every day on all of our
machines running KDE because they are written in C++ because they are
building upon Qt. That is a huge mistake.

>> Qt is a generation behind, generating code in a proprietary dialect of
>> C++ that could barely be less safe or interoperable.
> 
> This is only half of the truth: You can generate C++ code, but for a
> commercial project e.g. I save the GUI forms as XML, which are loaded by
> JavaScript, which is integrated in Qt and which has access to all GUI
> elements. The GC and prototype based programming style of JavaScript is
> very nice for GUI programming, e.g. you can use anonymous functions as
> button handlers with a very simple syntax.

What KDE applications are written in Javascript?

>> I cannot even use Qt
>> directly from OCaml and, if I could, any compiled binaries would be
>> brittle with respect to the exact versions on all libraries on my machine
>> so they would segfault on the vast majority of other machines. So the
>> only practical option is to distribute source code and ask users to
>> recompile it or distro maintainers to create custom packages for it. That
>> throws up barriers to commercial software on Linux.
> 
> This is wrong. There are many way how to use Qt: On Linux there is no 
> problem with different versions of libraries, because it has a descent
> version managment for shared libraries and you link your programs to the
> right version, which you can deliver with your application, if not already
> installed on the system.

No, Linux will happily dynamically load a binary incompatible library and
then segfault.

> To avoid any problems, you can even link it statically to your
> application. 

No, you can link it a ton of useless junk that you don't need, bloat your
downloadable executables by a factor of a 1,000 to drive customers away and
spend all of your remaining profits on bandwidth but you'll always be left
with some dynamic linking.

Have you even looked at what you're pulling in:

$ ldd /usr/lib/libqt-mt.so.3.3.8
        linux-gate.so.1 =>  (0xffffe000)
        libfontconfig.so.1 => /usr/lib/libfontconfig.so.1 (0xf7808000)
        libaudio.so.2 => /usr/lib/libaudio.so.2 (0xf77f2000)
        libXt.so.6 => /usr/lib/libXt.so.6 (0xf77a1000)
        libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0xf7782000)
        libpng12.so.0 => /usr/lib/libpng12.so.0 (0xf775e000)
        libz.so.1 => /usr/lib/libz.so.1 (0xf7749000)
        libXi.so.6 => /usr/lib/libXi.so.6 (0xf7741000)
        libXrender.so.1 => /usr/lib/libXrender.so.1 (0xf7738000)
        libXrandr.so.2 => /usr/lib/libXrandr.so.2 (0xf7730000)
        libXcursor.so.1 => /usr/lib/libXcursor.so.1 (0xf7727000)
        libXinerama.so.1 => /usr/lib/libXinerama.so.1 (0xf7724000)
        libXft.so.2 => /usr/lib/libXft.so.2 (0xf7711000)
        libfreetype.so.6 => /usr/lib/libfreetype.so.6 (0xf769a000)
        libXext.so.6 => /usr/lib/libXext.so.6 (0xf768c000)
        libX11.so.6 => /usr/lib/libX11.so.6 (0xf756d000)
        libSM.so.6 => /usr/lib/libSM.so.6 (0xf7565000)
        libICE.so.6 => /usr/lib/libICE.so.6 (0xf754d000)
        libdl.so.2 => /lib/i686/cmov/libdl.so.2 (0xf7549000)
        libpthread.so.0 => /lib/i686/cmov/libpthread.so.0 (0xf7530000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xf743f000)
        libm.so.6 => /lib/i686/cmov/libm.so.6 (0xf7418000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xf73ec000)
        libc.so.6 => /lib/i686/cmov/libc.so.6 (0xf728c000)
        libexpat.so.1 => /usr/lib/libexpat.so.1 (0xf7266000)
        libXau.so.6 => /usr/lib/libXau.so.6 (0xf7263000)
        libXfixes.so.3 => /usr/lib/libXfixes.so.3 (0xf725d000)
        libxcb.so.1 => /usr/lib/libxcb.so.1 (0xf7244000)
        libuuid.so.1 => /lib/libuuid.so.1 (0xf7240000)
        /lib/ld-linux.so.2 (0x56555000)
        libXdmcp.so.6 => /usr/lib/libXdmcp.so.6 (0xf723b000)

Have you considered what statically linking X11 would do?

What are you going to suggest next, that I bundle an OS with my application?

> I've just installed
> http://get.qtsoftware.com/qtsdk/qt-sdk-win-opensource-2009.03.exe
> Included in this release was even the compiler (based on MinGW) and with
> Qt Creator an IDE you don't need any other program to start programming.
> There is a demo, which just works, no "brittle" problems at all.

One of the demos works on another OS. Great.

>> And I suppose I would be expected to go back to battling with bugs in the
>> g++ toolchain? No thanks. I dropped that crappy language and
>> implementation years ago for good reasons and have no intention of going
>> backwards.
> 
> Does WPF even exists for Linux?

No, Linux has nothing comparable. Linux does not even have a VM or graphics
libraries capable of hosting WPF reliably. That was my point.

> On Windows Qt works with Visual Studio, which has not a perfect C++
> compiler, but still good quality.

So I can go back to a dying language *and* benefit from yesteryear's GUIs?
Yipee!

>>> wxWidgets has some nice GUI editors, too and it uses the native controls
>>> of the operating system, so I assume they are hardware accelerated, but
>>> why is this important for a GUI, if you just want to display some text
>>> and edit fields and not realtime 3D animation?
>> 
>> Are you seriously asking why someone developing a *graphical* user
>> interface might be interested in decent graphics?
> 
> I was thinking of warehouse applications, databases etc., but you are
> right that you need accelerated graphics for multimedia applications etc.
> Thanks Trolltech that they support it :-)

In a nice unsafe unintegrated unreliable out-of-date kind of way.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 1:50:57 AM

On Jul 10, 11:29=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:

> Are you assuming GCC and not Intel C++ (which often generates code that i=
s
> several times faster)?

[citation_needed]

IME they are neck to neck. Same for C++ vs Fortran (IFC and G77). ICC
gave me more problems, so I  dumped it.
0
Reply fft1976 (100) 7/11/2009 2:03:30 AM

ACL wrote:
>> >> So either Haskell is not "decent" or 200x slower is "not considerably
>> >> slower".
>
> You see here, the wiley troll makes a claim of comparison as if it is
> fact.

Err, it is fact and I cited the source.

> 'Haskell is 200x slower' than ...? he doesn't specify what it is 
> 200x slower than.

I explicitly wrote "200x slower than C++".

>> > Hmm.  This one took me about 10 minutes:
>>
>> > bwt :: B.ByteString -> B.ByteString
>> > bwt str =
>> > let sorted = map fst . sortBy (compare `on` snd) $ zip [0, 1..]
>> > (B.unpack str)
>> > slen   = B.length str
>> > in B.pack . map (\i -> B.index str ((i-1) `mod` slen)) $ sorted
> 
> The trolled posts something to prove that his language is productive.
> 
>> Your incomplete implementation is over 100x slower than bzip2. Moreover,
>> your Haskell runs out of memory when trying to compress only 8Mb.
> 
> The troll cleverly compares the 6 line haskell implementation to an
> industry quality implementation of zip compression,

Bzip2, not zip.

> specifically well known for its speed.

Did you want to compare Haskell with badly written inefficient C?

> The source of which being nearly 1 megabyte of information compressed.

No, the source code to bzip2 is 170kB in under 9kLOC. The "blocksort.c" file
that contains the equivalent of this code (and a lot more) and is only 729
LOC.

> We should note that it is only 100x slower than the high quality
> implementation, while the claim was that haskell would be 200x
> slower...

No, the partially-implemented Haskell is already 100x slower that the
complete C implementation so a full Haskell implementation based upon it
must be over 100x slower.

>> The poor performance of your Haskell code is a direct consequence of
>> Haskell's unpredictability. Obviously you failed to predict how bad your
>> code was or you would not have posted an example that contradicts your
>> own assertions.
> 
> He omits the fact that the poor performance is a result of not
> comparing apples to apples in any sort of reasonable manner.

You misunderstood the comparison.

> He also omits the fact that the author admited that it wasn't the highest
> quality implementation of zip compression.

Ertugrul claimed he could write performant Haskell and then didn't.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 2:19:19 AM

If you don't want to install Qt, I've found a video channel with some
demos:

http://www.youtube.com/user/QtStudios

I didn't know that they pronounce it "cute" :-)


Jon Harrop wrote:

> We experience dozens of segfaults from KDE apps every day on all of our
> machines running KDE because they are written in C++ because they are
> building upon Qt. That is a huge mistake.

You are right, C++ is not the best language for building higher level
software.

> What KDE applications are written in Javascript?

I don't know, maybe most are written in C++. At least there are some
projects for providing Qt and KDE bindings for scripting languages,
including e.g. C# :

http://techbase.kde.org/Development/Languages/Smoke

> No, Linux will happily dynamically load a binary incompatible library and
> then segfault.

This depends how it is configured. In Linux there is usually a library
called foo.so.3.4.5 and then links like foo.so.3.4 and foo.so.3, but maybe
even foo.so.2 for foo.so.3.4.5, if it is compatible. But you don't have to
create this links, if it is not compatible, so chances are very good, that
it doesn't load an incompatible library.

> No, you can link it a ton of useless junk that you don't need, bloat your
> downloadable executables by a factor of a 1,000 to drive customers away and
> spend all of your remaining profits on bandwidth but you'll always be left
> with some dynamic linking.
> 
> Have you even looked at what you're pulling in:
> 
> $ ldd /usr/lib/libqt-mt.so.3.3.8

[lots of standard libraries]

> Have you considered what statically linking X11 would do?

Of course, I don't want to link statically to libc6 or X11 :-) Only the Qt
libraries, the rest is standard on each modern Linux system. But in general
this is a problem. Unlike Windows, sometimes there are major incompatible
updates in Linux, e.g. if you have linked to libc5, it doesn't work with
libc6. But Microsoft has catched up in this direction: Some XP applications
doesn't work anymore in Vista :-)

For a typical application you have an offset of about 12 mb for Qt
(measured the unpacked size of the DLLs on Windows). This is big, but small
for modern applications. This means the user has to wait one minute for
downloading the application with a modern internet connection. Bandwith is
no problem theses days. E.g. in Germany there are hosting services with
unlimited traffic for 80 Euro per month, or you can distribute it with
Torrent or Sourceforge, for open source applications.

But you are right, this is not perfect. Please suggest Microsoft to bundle
the Qt DLLs with Windows.

> No, Linux has nothing comparable. Linux does not even have a VM or graphics
> libraries capable of hosting WPF reliably. That was my point.

Linux has many VMs, maybe you know this one:

http://www.mono-project.com

Looks like at least Winforms applications works with it. Should be not too
difficult to enhance it for WPF.

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/11/2009 2:48:53 AM

On 2009-07-10 20:05:50 -0400, the amphibian formerly known as toad said:

> Raffael Cavallaro wrote:
>> On 2009-07-10 17:09:41 -0400, Larry D'Anna <larry@elder-gods.org> said:
>>> They're a bit difficult to learn, but once you understand them they're
>>> not hard to use.
>> 
>> The point here is that it is completely unnecessary cognitive overhead.
> 
> All HLL features are "unnecessary cognitive overhead".

A feature is unnecessary when it gets in the way of a direct mapping to 
the problem domain. High or low level has nothing to do with it. It's a 
matter of appropriateness to the the domain. When the domain is about 
mutating state, then monads are inappropriate, not because they are 
"high level" but because they get in the way of a direct mapping from 
the problem domain to code.

-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/11/2009 4:11:53 AM

On Jul 10, 9:35=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Vend wrote:
> > Why?
> > Type safety is orthogonal to the functional/imperative distinction.
>
> Only in theory. In practice, functional languages (OCaml, Haskell) offer =
far
> more expressive type systems than any available safe imperative language
> implementation (Java, C#).

The issue under discussion was type safety, not type expressiveness.
And anyway, while modern functional languages do have expressive type
systems, this isn't necessarily a property of functional languages.

Algebraic types and type inference could be used in the definition of
an imperative language.
On the other hand, early lisps were largely functional languages, yet
they had poor type systems.

> >> Also purely functional languages (e.g. Haskell, Clean) and languages
> >> with immutable data (e.g. F#) allow clean and concise algorithm
> >> implementations, which are still just as fast as imperative variants
> >> with explicit reference/memory handling.
>
> > This makes no sense, since you can always use mutable variables as if
> > they were immutable.
>
> That does not recover the properties of purely functional data structures=
..

What properties?
If by convention you assign to each variable only once per lifetime,
you get the same properties of immutable variables.

Having a way to specify immutability in the language can be useful to
detect bugs, but it doesn't change the base semantics of the programs:
if you take a correct program written using immutable variables and
replace them with mutable variables, it stays correct.

0
Reply vend82 (230) 7/11/2009 8:50:07 AM

On Jul 10, 8:42=A0pm, Ertugrul S=F6ylemez <e...@ertes.de> wrote:
> > F# is not purely functional.
>
> So...?

I think we were discussing purely functional languages.

> > Type safety is orthogonal to the functional/imperative distinction.
>
> Type safety is one kind of safety. =A0The functional paradigm gives you
> other types of safety, too, which doesn't require additional language
> constructs like 'foreach'.

What kind of safety?

> That statement wasn't restricted to purely functional languages, but
> despite Dr. Harrop's usual noise purely functional languages perform
> quite well.

Do they?
Functional update of a data structure has both asymptotic and constant
performance penality over destructive update.

> > > Also purely functional languages (e.g. Haskell, Clean) and languages
> > > with immutable data (e.g. F#) allow clean and concise algorithm
> > > implementations, which are still just as fast as imperative variants
> > > with explicit reference/memory handling.
>
> > This makes no sense, since you can always use mutable variables as if
> > they were immutable.
>
> You cannot in the same convenient way.

Why not? You just have to assign each variable only once.
Language-level immutability can be useful as an optional constraint
for automatic program verification, but I don't see the point of
forcing it on all variables like purely functiona program do.

> =A0With immutable data you can make
> a function take a tree and return a slightly modified tree without much
> programming effort.

Yes, but it doesn't have to be whole-program language-enforced
immutability.
The Java 'final' keyword sufficies for that task.

> > What makes functional languages more coincise is the availability of
> > first-class procedures.
>
> Modern imperative languages have that as well. =A0Functional programming
> is a paradigm, not a tool.

Right. As a paradigm, functional programming can be useful.
As a language constraint, like in Haskell and Clean, it is not.

> > Lazy evaluation can also improve expressivity, at the cost of
> > performance problems.
>
> Lazy evaluation is a semantic property. =A0What it compiles to is a
> different question.

Time and particularly space complexity are also sematic properties,
and they are affected by lazy evaluation.

> =A0Particularly Haskell as the outrider in non-strict
> semantics does quite well at that (with GHC).

I've read that Haskell has unpredictable space complexity, which
depends on the inner workings of the compiler.

> > > Just in case you didn't notice, OCaml is a functional language.
>
> > But it is not pure.
>
> So...? =A0The OP obviously doesn't like functional programming. =A0That's=
 my
> point.

No.

0
Reply vend82 (230) 7/11/2009 9:28:40 AM

On Jul 11, 1:49=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry D'Anna wrote:
> > ["Followup-To:" header set to comp.lang.lisp.]
> > On 2009-07-10, Jon Harrop <j...@ffconsultancy.com> wrote:
> >> Here is a trivial counter example: mutate an element in an array in O(=
1).
>
> > easy.
>
> >http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html
>
> That is O(n) with GHC.

And anyway using state monads to re-implement imperative programming
on the top of a purely functional language running on an imperative
machine and interacting with a stateful world is a convoluted
abstraction inversion.
0
Reply vend82 (230) 7/11/2009 9:32:05 AM

On Jul 10, 8:55=A0pm, Larry D'Anna <la...@elder-gods.org> wrote:
> >> What's wrong with purely functional languages?
>
> > The "purely" part. Some solutions are naturally expressed in a pure
> > functional manner. Others are not. The programmer should have a choice.
>
> Uh, in Haskell you absolutely do have a choice. =A0Haskell gives the prog=
rammer
> access to all the non-functional things you want: mutable cells, mutable =
arrays,
> foreign functions, IO, etc. =A0You just have to use monads to get to it a=
ll. =A0You
> can take any imperative algorithm you like and translate it into Haskell =
in a
> totally straightforward way. =A0

Hence you need extra complexity to implement something you get for
free in imperative languages.
What is the point?
0
Reply vend82 (230) 7/11/2009 9:41:37 AM

On Jul 10, 9:04=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > On Jul 10, 1:10=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> >> Larry Coleman wrote:
> >> > I think a better approach for the rest of us is to find one or more
> >> > platforms that are "good enough" (CL and Haskell both work for me) a=
nd
> >> > start coding apps and libraries.
>
> >> I think that is an extremely bad idea because you're building on sand.
> >> The very foundation of your applications and libraries is rotting.
>
> > What does this even mean?

Apparently this was the question I shouldn't have asked because I
should have known I wouldn't like the answer.

>
> No attempt is being made to factor out the enormous amount of commonality
> between those code bases (e.g. SBCL and GHC). For example, the garbage
> collectors and the foreign function interfaces.
>
> Hence Linux has a dozen different uninteroperable functional language
> implementations each with completely separate GC implementations, none of
> which are up to date with respect to important functionality like
> concurrent collection.
>
OK, hands up, everyone who guessed in advance that this is what was
meant by "rotting foundation" and "building on sand."

0
Reply larryliberty (26) 7/11/2009 10:06:02 AM

On Jul 11, 10:50=A0am, Vend <ven...@virgilio.it> wrote:
>
> The issue under discussion was type safety, not type expressiveness.

These are interdependent. A more expressive type system requires fewer
work-arounds with unsafe operations such as downcasts, and allows
encoding domain-specific safety and correctness properties in types,
making the notion of type safety stronger.

> And anyway, while modern functional languages do have expressive type
> systems, this isn't necessarily a property of functional languages.
>
> Algebraic types and type inference could be used in the definition of
> an imperative language.

Hindley/Milner style polymorphic type inference - which is what all
those functional languages are based on - does not work for imperative
features. For an imperative language you are forced to use more ad-hoc
and less complete approaches.

> > > This makes no sense, since you can always use mutable variables as if
> > > they were immutable.
>
> > That does not recover the properties of purely functional data structur=
es.
>
> What properties?
> If by convention you assign to each variable only once per lifetime,
> you get the same properties of immutable variables.

When you build an abstraction you cannot simply assume that client
code behaves well. Ensuring (never mind proving) abstraction safety is
orders of magnitude harder in the presence of mutable state. The whole
cottage industry around ownership types is one attempt to tame mutable
state in this respect.

> Having a way to specify immutability in the language can be useful to
> detect bugs, but it doesn't change the base semantics of the programs:
> if you take a correct program written using immutable variables and
> replace them with mutable variables, it stays correct.

That is patently false (unless you only consider whole programs, which
is not very useful). The presence of mutable state fundamentally
changes the semantic notion of program equivalence. In a language with
state, if you put your program P into the context C of another program
(ie. your "program" is a module or class that is used in a larger
program), C can generally distinguish more possible behaviours of P
than in a language with immutable variables - which is a technical way
of saying that it has more ways to mess with it. The flipside is that
you have to work harder to write P such that no C can break its
intended semantics. The most obvious (but by no means sufficient) rule
is that P should never pass out parts of its internal representation,
but always has to copy it first. That is no concern with immutable
data structures.

- Andreas
0
Reply rossberg1 (19) 7/11/2009 10:38:30 AM

Jon Harrop wrote:
> Larry D'Anna wrote:
> > ["Followup-To:" header set to comp.lang.lisp.]
> > On 2009-07-10, Jon Harrop <j...@ffconsultancy.com> wrote:
> >> Here is a trivial counter example: mutate an element in an array in O(1).
>
> > easy.
>
> >http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html
>
> That is O(n) with GHC.

It is O(1) for unboxed arrays.

--
Johannes Laire
0
Reply johannes.laire (2) 7/11/2009 10:46:48 AM

On Jul 11, 12:38=A0pm, Andreas Rossberg <rossb...@mpi-sws.org> wrote:
> On Jul 11, 10:50=A0am, Vend <ven...@virgilio.it> wrote:
>
>
>
> > The issue under discussion was type safety, not type expressiveness.
>
> These are interdependent. A more expressive type system requires fewer
> work-arounds with unsafe operations such as downcasts, and allows
> encoding domain-specific safety and correctness properties in types,
> making the notion of type safety stronger.

Ok, I meant the property of the language not to fall into unspecified
behavior when a type error occours, like C and C++ can do.

> Hindley/Milner style polymorphic type inference - which is what all
> those functional languages are based on - does not work for imperative
> features. For an imperative language you are forced to use more ad-hoc
> and less complete approaches.

Can you provide an example, please?

> > What properties?
> > If by convention you assign to each variable only once per lifetime,
> > you get the same properties of immutable variables.
>
> When you build an abstraction you cannot simply assume that client
> code behaves well. Ensuring (never mind proving) abstraction safety is
> orders of magnitude harder in the presence of mutable state. The whole
> cottage industry around ownership types is one attempt to tame mutable
> state in this respect.

As I said, immutable variables can be useful for program verification.
You can write in the documentation of your modules "don't mutate these
objects", and hope that the client complies, but if the language
allows you to express that contract in the type system then it is
useful to do so and avoid errors.

However, I see no point in making all variables immutable, or even in
making variables immutable by default.

> > Having a way to specify immutability in the language can be useful to
> > detect bugs, but it doesn't change the base semantics of the programs:
> > if you take a correct program written using immutable variables and
> > replace them with mutable variables, it stays correct.
>
> That is patently false (unless you only consider whole programs, which
> is not very useful). The presence of mutable state fundamentally
> changes the semantic notion of program equivalence. In a language with
> state, if you put your program P into the context C of another program
> (ie. your "program" is a module or class that is used in a larger
> program), C can generally distinguish more possible behaviours of P
> than in a language with immutable variables - which is a technical way
> of saying that it has more ways to mess with it.

No, since you can represent state with input and output values.

> The flipside is that
> you have to work harder to write P such that no C can break its
> intended semantics. The most obvious (but by no means sufficient) rule
> is that P should never pass out parts of its internal representation,
> but always has to copy it first. That is no concern with immutable
> data structures.
>
> - Andreas

0
Reply vend82 (230) 7/11/2009 11:02:25 AM

On Jul 11, 1:02=A0pm, Vend <ven...@virgilio.it> wrote:
>
> > Hindley/Milner style polymorphic type inference - which is what all
> > those functional languages are based on - does not work for imperative
> > features. For an imperative language you are forced to use more ad-hoc
> > and less complete approaches.
>
> Can you provide an example, please?

The simplest possible example: when you declare

  val x =3D nil

where nil denotes the empty list, then in case x is immutable,
inference can assign the polymorphic type

  x : List[A]

If x is mutable, it cannot, because that would be unsound. Similar
problems occur with subtyping polymorphism, essentially because
mutable variables always have to be invariant.


> However, I see no point in making all variables immutable, or even in
> making variables immutable by default.

The idea is that the language (and its type system) should cleanly
separate the notions of variable and mutable state. That makes the
intent clear, allows for more flexible typing, and most importantly,
avoids accident. That is what functional languages do (all of which
allow mutable state in one form or the other).


> > > Having a way to specify immutability in the language can be useful to
> > > detect bugs, but it doesn't change the base semantics of the programs=
:
> > > if you take a correct program written using immutable variables and
> > > replace them with mutable variables, it stays correct.
>
> > That is patently false (unless you only consider whole programs, which
> > is not very useful). The presence of mutable state fundamentally
> > changes the semantic notion of program equivalence. In a language with
> > state, if you put your program P into the context C of another program
> > (ie. your "program" is a module or class that is used in a larger
> > program), C can generally distinguish more possible behaviours of P
> > than in a language with immutable variables - which is a technical way
> > of saying that it has more ways to mess with it.
>
> No, since you can represent state with input and output values.

Not sure what you are saying. If your language has higher-order state
- i.e. pointers or closures - then you cannot do that (except as a
whole program transformation).

- Andreas
0
Reply rossberg1 (19) 7/11/2009 12:39:37 PM

Jon Harrop <jon@ffconsultancy.com> wrote:

> > He also omits the fact that the author admited that it wasn't the
> > highest quality implementation of zip compression.
>
> Ertugrul claimed he could write performant Haskell and then didn't.

Or maybe you should learn to use the compiler properly.  The code works
well for me.  High memory usage comes from the sorting algorithm
(because it uses lists), which I said can be improved.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/11/2009 1:58:37 PM

Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> wrote:

> >>> They're a bit difficult to learn, but once you understand them
> >>> they're not hard to use.
> >>
> >> The point here is that it is completely unnecessary cognitive
> >> overhead.
> >
> > All HLL features are "unnecessary cognitive overhead".
>
> A feature is unnecessary when it gets in the way of a direct mapping
> to the problem domain. High or low level has nothing to do with
> it. It's a matter of appropriateness to the the domain. When the
> domain is about mutating state, then monads are inappropriate, not
> because they are "high level" but because they get in the way of a
> direct mapping from the problem domain to code.

State monads _are_ a direct mapping.  Monads allow you to create small
problem-specific languages.  The problem in this case is state and state
monads encode it in a concise and elegant way, particularly because you
don't lose referential transparency along the way.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/11/2009 2:08:11 PM

Larry D'Anna <larry@elder-gods.org> wrote:

> > Here is a trivial counter example: mutate an element in an array in
> > O(1).
>
> easy.
>
> http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html

There is also DiffArray which doesn't require any monad.  Unfortunately
it's slower than STArray and STUArray, which give you C-like speed, so
if you want high performance, STArrays/STUArrays are the way to go.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/11/2009 2:12:01 PM

Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> wrote:

> > And we all know that humans are far from perfect.  They make
> > mistakes all the time just because of that cognitive property.
> > Safety is all about restricting this or finding alternatives.
>
> And expressiveness is all about *not* restricting the ability to write
> the solution in the language of the problem domain just because of
> some misplaced notion of "safety."

You may want to show me something that couldn't be implemented in
Haskell, or where the additional safety gets in your way.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/11/2009 2:13:52 PM

On 2009-07-11 10:13:52 -0400, Ertugrul S�ylemez <es@ertes.de> said:

> You may want to show me something that couldn't be implemented in
> Haskell, or where the additional safety gets in your way.

"couldn't be implemented" is a turing tarpit red herring. For "gets in 
your way," upthread we've just been discussing the pointless need to 
use monads just to get simple mutable state.

-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/11/2009 3:21:55 PM

On 2009-07-11 10:08:11 -0400, Ertugrul S�ylemez <es@ertes.de> said:

> State monads _are_ a direct mapping.

Introducing some intermediation, such as monads, is, by definition, not 
*direct*.

-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/11/2009 3:25:25 PM

On Fri, 10 Jul 2009 21:09:41 +0000, Larry D'Anna wrote:

>>> You just have to use monads to get to it all.  You
>>> can take any imperative algorithm you like and translate it into
>>> Haskell in a totally straightforward way.
>>
>> monads. straightforward. <= contradiction in terms
> 
> They're a bit difficult to learn, but once you understand them they're
> not hard to use.

They're not difficult to learn in the slightest. You could teach someone
how to use Haskell's "IO" without ever mentioning either the word "monad"
or the concepts behind it.

What imperative programmers seem to dislike is that monads take the
fundamental nature of imperative languages and turn it into a "thing".

0
Reply nobody (4804) 7/11/2009 4:51:17 PM

Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> writes:
> Introducing some intermediation, such as monads, is, by definition,
> not *direct*.

That sentence would be equally true if you replaced the word "monads"
with "keystrokes". 
0
Reply phr.cx (5483) 7/11/2009 5:27:38 PM

On 2009-07-10, Jon Harrop <jon@ffconsultancy.com> wrote:
> Larry D'Anna wrote:
>> ["Followup-To:" header set to comp.lang.lisp.]
>> On 2009-07-10, Jon Harrop <jon@ffconsultancy.com> wrote:
>>> Here is a trivial counter example: mutate an element in an array in O(1).
>> 
>> easy.
>> 
>> http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html
>
> That is O(n) with GHC.

$ cat stupid.hs 

import CPUTime
import System.IO
import Prelude
import Control.Monad.ST
import Data.Array.ST
import Data.Array

fill a i n = if i > n 
                then return ()
                else do writeArray a i i 
                        fill a (i+1) n 

count n = do a <- newArray (1,n) 0 :: ST s (STUArray s Int Int)
             fill a 1 n 
             return ()

bench n = do t1 <- getCPUTime
             stToIO $ count n 
             t2 <- getCPUTime 
             print $ round $ toRational(t2 - t1) / toRational n

main = do bench 10000
          bench 100000
          bench 1000000
          bench 10000000

$ ghc stupid.hs
$ ./a.out
1200000
1000070
1016063
1002063
$ echo Jon Harrop is a loud-mouthed idiot.
Jon Harrop is a loud-mouthed idiot.
$

0
Reply larry4779 (10) 7/11/2009 6:06:27 PM

On 2009-07-11, Johannes Laire <johannes.laire@gmail.com> wrote:
> Jon Harrop wrote:
>> Larry D'Anna wrote:
>> > ["Followup-To:" header set to comp.lang.lisp.]
>> > On 2009-07-10, Jon Harrop <j...@ffconsultancy.com> wrote:
>> >> Here is a trivial counter example: mutate an element in an array in O(1).
>>
>> > easy.
>>
>> >http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html
>>
>> That is O(n) with GHC.
>
> It is O(1) for unboxed arrays.

I thought it was O(1) for boxed arrays too, but I tested it and defiantly is
not.  Any idea why boxed vs. unboxed should make a difference?

      --larry

0
Reply larry4779 (10) 7/11/2009 6:19:28 PM

Ertugrul Söylemez wrote:
> Jon Harrop <jon@ffconsultancy.com> wrote:
>> > He also omits the fact that the author admited that it wasn't the
>> > highest quality implementation of zip compression.
>>
>> Ertugrul claimed he could write performant Haskell and then didn't.
> 
> Or maybe you should learn to use the compiler properly.

You claimed "most decent functional languages aren't considerably slower
than C" and then provided Haskell that is over 100x slower than C.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 6:43:42 PM

Ertugrul Söylemez wrote:
> Vend <vend82@virgilio.it> wrote:
>> However, if I understand correctly, purely functional languages
>> typically have performance problems.
> 
> That statement wasn't restricted to purely functional languages, but
> despite Dr. Harrop's usual noise purely functional languages perform
> quite well.

Your fastest BWT in Haskell is still over 100x slower than C.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 6:53:12 PM

Vend wrote:
> On Jul 10, 8:42 pm, Ertugrul Söylemez <e...@ertes.de> wrote:
>> > F# is not purely functional.
>> That statement wasn't restricted to purely functional languages, but
>> despite Dr. Harrop's usual noise purely functional languages perform
>> quite well.
> 
> Do they?
> Functional update of a data structure has both asymptotic and constant
> performance penality over destructive update.

In theory, you can always fall back on monads to let you write imperative
code in a purely functional language.

In practice, the infrastructure is not there. Hence filling a hash table in
Haskell is 30x slower than in F#.

>> Particularly Haskell as the outrider in non-strict
>> semantics does quite well at that (with GHC).
> 
> I've read that Haskell has unpredictable space complexity, which
> depends on the inner workings of the compiler.

Look at Ertugrul's Haskell implementation of BWT in this thread. Aside from
being slow, it consumes asymptotically more memory than expected.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 7:00:01 PM

Jon Harrop wrote:

> Syntax: Indentation-sensitive syntax as in Python, Haskell and F# was a huge
> design mistake because cut'n'paste from a browser can break code
> semantically by altering the indentation, and it prohibits autoindentation
> leaving you to reindent huge swaths of code by hand. Lisps got it wrong by
> oversimplifying the syntax, making math particularly cumbersome. OCaml got
> it wrong mainly by being too complex (e.g. a dozen different kinds of
> brackets instead of consistent brackets and identifiers to distinguish
> between lists, arrays, streams etc.) and by using unconventional operators
> (e.g. ** for power and ^ for string concatenation).

I've written some code in Python some time ago, e.g. this one:

http://www.frank-buss.de/shapeways/dome.py

It can be executed in Blender to create platonic solids and geodesic domes:

http://www.shapeways.com/model/28414/platonic_solids.html
http://www.shapeways.com/model/28981/geodesic_dome.html

Python is not that bad and I like the indention, because you'll see
immediatly how the code is meant. There is no wrong indention, like it is
possible in other languages, because then your code doesn't work. Fix the
web pages from where you want to paste, not the language :-)

-- 
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
0
Reply fb (1526) 7/11/2009 7:05:05 PM

Ertugrul Söylemez wrote:
> Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com>
> wrote:
>> > And we all know that humans are far from perfect.  They make
>> > mistakes all the time just because of that cognitive property.
>> > Safety is all about restricting this or finding alternatives.
>>
>> And expressiveness is all about *not* restricting the ability to write
>> the solution in the language of the problem domain just because of
>> some misplaced notion of "safety."
> 
> You may want to show me something that couldn't be implemented in
> Haskell, or where the additional safety gets in your way.

A Haskell implementation of the BWT sort that gets within 2x the performance
of C.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 7:10:20 PM

Larry Coleman wrote:
> OK, hands up, everyone who guessed in advance that this is what was
> meant by "rotting foundation" and "building on sand."

Do you not agree that the state of FPL implementations on Linux would be
vastly better if we had a decent VM to build upon?

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 7:15:46 PM

Johannes Laire wrote:
> Jon Harrop wrote:
>> Larry D'Anna wrote:
>> > ["Followup-To:" header set to comp.lang.lisp.]
>> > On 2009-07-10, Jon Harrop <j...@ffconsultancy.com> wrote:
>> >> Here is a trivial counter example: mutate an element in an array in
>> >> O(1).
>>
>> > easy.
>>
>> >http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html
>>
>> That is O(n) with GHC.
> 
> It is O(1) for unboxed arrays.

O(n) in general.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 7:16:46 PM

Larry D'Anna wrote:
> On 2009-07-10, Jon Harrop <jon@ffconsultancy.com> wrote:
>> That is O(n) with GHC.
> 
> $ cat stupid.hs
> 
> import CPUTime
> import System.IO
> import Prelude
> import Control.Monad.ST
> import Data.Array.ST
> import Data.Array
> 
> fill a i n = if i > n
>                 then return ()
>                 else do writeArray a i i
>                         fill a (i+1) n
> 
> count n = do a <- newArray (1,n) 0 :: ST s (STUArray s Int Int)
>              fill a 1 n
>              return ()
> 
> bench n = do t1 <- getCPUTime
>              stToIO $ count n
>              t2 <- getCPUTime
>              print $ round $ toRational(t2 - t1) / toRational n
> 
> main = do bench 10000
>           bench 100000
>           bench 1000000
>           bench 10000000
> 
> $ ghc stupid.hs
> $ ./a.out
> 1200000
> 1000070
> 1016063
> 1002063

Fill the array with the list [i] instead of the integer i and you get:

0
240010
552034
3161398

That is clearly not O(1).

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 7:51:07 PM

Larry D'Anna wrote:
> On 2009-07-11, Johannes Laire <johannes.laire@gmail.com> wrote:
>> Jon Harrop wrote:
>>> Larry D'Anna wrote:
>>> > ["Followup-To:" header set to comp.lang.lisp.]
>>> > On 2009-07-10, Jon Harrop <j...@ffconsultancy.com> wrote:
>>> >> Here is a trivial counter example: mutate an element in an array in
>>> >> O(1).
>>>
>>> > easy.
>>>
>>> >http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html
>>>
>>> That is O(n) with GHC.
>>
>> It is O(1) for unboxed arrays.
> 
> I thought it was O(1) for boxed arrays too, but I tested it and defiantly
> is not.  Any idea why boxed vs. unboxed should make a difference?

The write barrier incurred when mutating a boxed element in an array dirties
the whole array and that causes the GC to traverse the whole array at every
minor/gen0 GC, which is periodic (separated by constant amounts of time for
the purposes of this description). That dirtying is not necessary for
unboxed elements so you do not see the asymptotic performance degradation
with them, e.g. the STUArray of Int in your example.

My question is: can you always get the O(1) for all types of array (e.g. an
array of lists)? I had assumed that inherently boxed types such as lists
required the use of STArray instead of STUArray.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/11/2009 7:56:22 PM

On Fri, 10 Jul 2009 17:26:14 +0100, Jon Harrop <jon@ffconsultancy.com> said:

> Vassil Nikolov wrote:
>> On Fri, 10 Jul 2009 00:32:57 +0100, Jon Harrop <jon@ffconsultancy.com>
>> said:
>>> ...
>>> unconventional operators (e.g. ** for power ...)
>> 
>> That is an at-least-55-year-old convention.  How much more
>> conventional can it get?

> Superscript is more conventional.

  Oh I see.  I thought we were talking about programming language
  conventions for writing expressions with a keyboard.  Silly me.

  ---Vassil.


-- 
"Even when the muse is posting on Usenet, Alexander Sergeevich?"
0
Reply vnikolov1 (276) 7/11/2009 8:01:09 PM

Xah Lee <xahlee@gmail.com> wrote on Fri, 10 Jul 2009:
> i ask myself whether i have achieved something about creating a book length
> collection of my ideas and opinions. I must say yes i have.

You've got the length, that's for sure.  But usually a successful book is
about something more than just total word count.

I'd love to see you attempt to turn your collection into an actual published
book.  Most people here don't want to read your writings when you offer them
for free!  It would be amusing to see you attempt to get people to _pay_ for
the experience.

> But to quip, why are YOU not interested in lisp?? if not, why r u here?? 
> arn't u trolling?

But I _am_ interested in Lisp (unlike you).  That's (one of the very many)
differences between us.

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               don@geddis.org
Not what we have but what we enjoy, constitutes our abundance.
	-- Epicurus (Greek philosopher, BC 341-270)
0
Reply don8867 (556) 7/11/2009 8:43:24 PM

Jon Harrop <jon@ffconsultancy.com> wrote on Sat, 11 Jul 2009:
> Don Geddis wrote:
>> Xah Lee <xahlee@gmail.com> wrote on Thu, 9 Jul 2009 :
>>> In my opinion:
>>> lisp = useless old shit.
>> So, why do you post on this newsgroup, c.l.l?  It's clearly for people who
>> are interested in Lisp.  If you're not, why are you here?
> Is c.l.lisp only for pro-Lisp misinformation?

One would generally think it's for people that are at least invested in the
future of Lisp, if not the present.  Constructive criticism is fine.  Notice
that I said "interested in Lisp", not just "pro-Lisp" as you suggested.
Those phrases are not the same, and that distinction is critical.

If you think there's no value here, what are you achieving by entering this
community of people who _do_ think there is value, and constantly emitting
your boring refrain of, "there is no value here"?  You're just being
annoying, and making people angry to no constructive purpose.  Why bother?

Why not just go find a community of people who share the values that you
have, and be constructive with them?

The answer, of course, is obvious.  It's because adding negative energy to a
constructive conversation is actually the goal of such people.  They enjoy
seeing the existing community of well-intentioned people waste their time and
effort attempting to combat the troll.  There is no higher purpose to the
troll.  Being a troll is the whole point.

Most trolls gain at least some of their power, such as it is, by trying to
pretend that they're constructive members of the community.  I enjoy
occasionally pointing out the hypocrisy and deception in their writings.

        -- Don
_______________________________________________________________________________
Don Geddis                  http://don.geddis.org/               don@geddis.org
If the bark is the skin of the tree, then what are the acorns?  You don't want
to know.  -- Deep Thoughts, by Jack Handey [1999]
0
Reply don8867 (556) 7/11/2009 8:53:18 PM

On Jul 11, 3:15=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > OK, hands up, everyone who guessed in advance that this is what was
> > meant by "rotting foundation" and "building on sand."
>
> Do you not agree that the state of FPL implementations on Linux would be
> vastly better if we had a decent VM to build upon?
>

I'm not in the business of implementing functional languages, so I
don't know whether that's true, and frankly don't care.

Also, it takes some serious flexibility to make "rotting foundation"
and "building on sand" mean the same thing as "would be vastly
better." Most people can't stretch that far.
0
Reply larryliberty (26) 7/11/2009 9:24:03 PM

Larry Coleman wrote:
> On Jul 11, 3:15 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Larry Coleman wrote:
>> > OK, hands up, everyone who guessed in advance that this is what was
>> > meant by "rotting foundation" and "building on sand."
>>
>> Do you not agree that the state of FPL implementations on Linux would be
>> vastly better if we had a decent VM to build upon?
> 
> I'm not in the business of implementing functional languages, so I
> don't know whether that's true, and frankly don't care.

Ok. I care.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/12/2009 12:04:43 AM

On Sun, 12 Jul 2009 01:52:34 +0100, Jon Harrop <jon@ffconsultancy.com> said:

> Vassil Nikolov wrote:
>> On Fri, 10 Jul 2009 17:26:14 +0100, Jon Harrop <jon@ffconsultancy.com>
>> said:
>>> Vassil Nikolov wrote:
>>>> On Fri, 10 Jul 2009 00:32:57 +0100, Jon Harrop <jon@ffconsultancy.com>
>>>> said:
>>>>> ...
>>>>> unconventional operators (e.g. ** for power ...)
>>>> 
>>>> That is an at-least-55-year-old convention.  How much more
>>>> conventional can it get?
>>> 
>>> Superscript is more conventional.
>> 
>> Oh I see.  I thought we were talking about programming language
>> conventions for writing expressions with a keyboard.  Silly me.

> I was talking about conventions for writing expressions with a keyboard.
> LaTeX and Mathematica can both use superscript to denote power and in both
> cases it is typed with ^.

  Then we are not comparing `**' and superscripting for
  exponentiation, but `**' and `^'.  The latter convention (which
  originated in the form of an upward-pointing arrow) is more recent
  by a few years.

  ---Vassil.


-- 
"Even when the muse is posting on Usenet, Alexander Sergeevich?"
0
Reply vnikolov1 (276) 7/12/2009 12:39:42 AM

Vassil Nikolov wrote:
> On Fri, 10 Jul 2009 17:26:14 +0100, Jon Harrop <jon@ffconsultancy.com>
> said:
>> Vassil Nikolov wrote:
>>> On Fri, 10 Jul 2009 00:32:57 +0100, Jon Harrop <jon@ffconsultancy.com>
>>> said:
>>>> ...
>>>> unconventional operators (e.g. ** for power ...)
>>> 
>>> That is an at-least-55-year-old convention.  How much more
>>> conventional can it get?
>>
>> Superscript is more conventional.
> 
>   Oh I see.  I thought we were talking about programming language
>   conventions for writing expressions with a keyboard.  Silly me.

I was talking about conventions for writing expressions with a keyboard.
LaTeX and Mathematica can both use superscript to denote power and in both
cases it is typed with ^.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/12/2009 12:52:34 AM

On Jul 10, 10:19=A0pm, wrote:
> ACL wrote:
> >> >> So either Haskell is not "decent" or 200x slower is "not considerab=
ly
> >> >> slower".
>
> > You see here, the wiley troll makes a claim of comparison as if it is
> > fact.
>
> Err, it is fact and I cited the source.

No you didn't. I just scrolled up. I see no study cited.

> > 'Haskell is 200x slower' than ...? he doesn't specify what it is
> > 200x slower than.
>
> I explicitly wrote "200x slower than C++".
>
Who cares about C++?

It seems that any language you defame has to go up against 3 or 4
different languages of your choosing depending on the test. I thought
you were the F#/OCaml schill?

Besides the haskell was *according to you* only 100x slower than C
code, (not C++ code). you claimed 200x

>
> >> > Hmm. =A0This one took me about 10 minutes:
>
> >> > bwt :: B.ByteString -> B.ByteString
> >> > bwt str =3D
> >> > let sorted =3D map fst . sortBy (compare `on` snd) $ zip [0, 1..]
> >> > (B.unpack str)
> >> > slen =A0 =3D B.length str
> >> > in B.pack . map (\i -> B.index str ((i-1) `mod` slen)) $ sorted
>
> > The trolled posts something to prove that his language is productive.
>
> >> Your incomplete implementation is over 100x slower than bzip2. Moreove=
r,
> >> your Haskell runs out of memory when trying to compress only 8Mb.
>
> > The troll cleverly compares the 6 line haskell implementation to an
> > industry quality implementation of zip compression,
>
> Bzip2, not zip.
>

nitpicking doesn't make you more right.

> > specifically well known for its speed.
>
> Did you want to compare Haskell with badly written inefficient C?
>
if it is badly written and inefficient haskell... then yes.

> > The source of which being nearly 1 megabyte of information compressed.
>
> No, the source code to bzip2 is 170kB in under 9kLOC. The "blocksort.c" f=
ile
> that contains the equivalent of this code (and a lot more) and is only 72=
9
> LOC.
>



That's weird i just downloaded the source and zipped it came in at
~800kb.

Even if what you say is right, you are still comparing 100x more LOC.
Only 730 loc? Seriously?

> > We should note that it is only 100x slower than the high quality
> > implementation, while the claim was that haskell would be 200x
> > slower...
>
> No, the partially-implemented Haskell is already 100x slower that the
> complete C implementation so a full Haskell implementation based upon it
> must be over 100x slower.
>

That doesn't make sense. Adding code is not equal to adding extra run
time. Sometimes adding code makes things faster, you know.

> >> The poor performance of your Haskell code is a direct consequence of
> >> Haskell's unpredictability. Obviously you failed to predict how bad yo=
ur
> >> code was or you would not have posted an example that contradicts your
> >> own assertions.
>
> > He omits the fact that the poor performance is a result of not
> > comparing apples to apples in any sort of reasonable manner.
>
> You misunderstood the comparison.
>

It seems it is a bad comparison....

> > He also omits the fact that the author admited that it wasn't the highe=
st
> > quality implementation of zip compression.
>
> Ertugrul claimed he could write performant Haskell and then didn't.
>

I think he claimed it could be written, not that he was writing it.
0
Reply anonymous.c.lisper (176) 7/12/2009 3:16:27 AM

On 2009-07-11 13:27:38 -0400, Paul Rubin <http://phr.cx@NOSPAM.invalid> said:

> Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> writes:
>> Introducing some intermediation, such as monads, is, by definition,
>> not *direct*.
> 
> That sentence would be equally true if you replaced the word "monads"
> with "keystrokes".

Only in a world where programs can be conveyed to the machine 
telepathically. But then I'm sure you'd chime in about replacing 
"keystrokes" with "thoughts."

It's kind of sad when people jump on the phrasing rather than trying to 
make actual sense. We're clearly talking about *unncessary* additional 
means to accomplish a task, not the need to use keystrokes to type text.

I'll just say: "Introducing some *unnecessary* intermediation, such as 
monads, is, by definition, not *direct*." Is your inner pedant happy 
now?

-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/12/2009 3:47:27 AM

On 2009-07-11 12:51:17 -0400, Nobody <nobody@nowhere.com> said:

> They're not difficult to learn in the slightest. You could teach someone
> how to use Haskell's "IO" without ever mentioning either the word "monad"
> or the concepts behind it.

But they wouldn't have "learned" monads in that case at all; they'd 
just be doing voodoo programming (i.e., going throught the prescribed 
motions without understanding what it is they were doing)

> 
> What imperative programmers seem to dislike is that monads take the
> fundamental nature of imperative languages and turn it into a "thing".

No, what programmers who haven't drunk the *pure*-functional kool aid 
dislike about them is that they are just another form of unnecessary 
boiler plate that gets in the way of simply stating directly what the 
programmer wants to do. (That they're a pretentious form of boiler 
plate doesn't help their popularity much either. "Our language doesn't 
deal in dirty, impure, mutation, no, no! We use category theory 
instead!")


-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/12/2009 3:57:23 AM

Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> writes:
> I'll just say: "Introducing some *unnecessary* intermediation, such as
> monads, is, by definition, not *direct*." Is your inner pedant happy now?

I could say that traditional effectful computation, in whatever
language, is already done in a monad.  Haskell just makes this
explicit.
0
Reply phr.cx (5483) 7/12/2009 4:32:01 AM

Raffael Cavallaro wrote:
> On 2009-07-11 12:51:17 -0400, Nobody <nobody@nowhere.com> said:
>> What imperative programmers seem to dislike is that monads take the
>> fundamental nature of imperative languages and turn it into a "thing".
> 
> No, what programmers who haven't drunk the *pure*-functional kool aid
> dislike about them is that they are just another form of unnecessary
> boiler plate that gets in the way of simply stating directly what the
> programmer wants to do.

Indeed. We saw a nice example of that elsewhere on this very thread. Here is
a simple OCaml program that fills in an array by mutating elements in O(1):

let bench n =
  let t = Sys.time() in
  ignore(Array.init n (fun i -> [i]));
  Printf.printf "%gs\n%!" ((Sys.time() -. t) *. 1e6 /. float n)

let () =
  List.iter bench [10000; 100000; 1000000; 10000000]

Here is the Haskell equivalent that fills in an STArray by mutating elements
in O(n):

import CPUTime
import System.IO
import Prelude
import Control.Monad.ST
import Data.Array.ST
import Data.Array

fill a i n = if i > n
                then return ()
                else do writeArray a i [i]
                        fill a (i+1) n

count n = do a <- newArray (1,n) [0] :: ST s (STArray s Int [Int])
             fill a 1 n
             return ()

bench n = do t1 <- getCPUTime
             stToIO $ count n
             t2 <- getCPUTime
             print $ round $ toRational(t2 - t1) / toRational n

main = do bench 10000
          bench 100000
          bench 1000000
          bench 10000000

The presence of monads raises many immediate questions:

Why is this an STArray instead of an Array or STUArray or IOArray or
IOUArray?

Why must the programmer manually annotate the following type:

  ST s (STArray s Int [Int])

when other languages with type inference (e.g. SML, OCaml, F#) do not
require such type annotations?

Why is "stToIO" needed?

The Haskell is far more verbose than the OCaml and uses many functions. Is
this because each function requires a separate "do" because the imperative
sections of code must be wrapped individually in monadic "do" notation?

How could I refactor this to use a more conventional "time" combinator?

The answers to these questions are not at all obvious to me or, indeed, to
the vast majority of Haskell programmers who tinker with it without
realising important facts like mutating an element in an array in O(n).

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/12/2009 5:40:04 AM

ACL wrote:
> On Jul 10, 10:19 pm, wrote:
>> ACL wrote:
>> >> >> So either Haskell is not "decent" or 200x slower is "not
>> >> >> considerably slower".
>>
>> > You see here, the wiley troll makes a claim of comparison as if it is
>> > fact.
>>
>> Err, it is fact and I cited the source.
> 
> No you didn't. I just scrolled up. I see no study cited.

Here's that citation again:

http://www.mail-archive.com/haskell-cafe%40haskell.org/msg25645.html

>> > 'Haskell is 200x slower' than ...? he doesn't specify what it is
>> > 200x slower than.
>>
>> I explicitly wrote "200x slower than C++".
>
> Who cares about C++?
> 
> It seems that any language you defame has to go up against 3 or 4
> different languages of your choosing depending on the test. I thought
> you were the F#/OCaml schill?
> 
> Besides the haskell was *according to you* only 100x slower than C
> code, (not C++ code). you claimed 200x

The post I cited claimed 200.

>> > specifically well known for its speed.
>>
>> Did you want to compare Haskell with badly written inefficient C?
>
> if it is badly written and inefficient haskell... then yes.

We are trying to determine whether or not Haskell code can be efficient.

>> > The source of which being nearly 1 megabyte of information compressed.
>>
>> No, the source code to bzip2 is 170kB in under 9kLOC. The "blocksort.c"
>> file that contains the equivalent of this code (and a lot more) and is
>> only 729 LOC.
> 
> That's weird i just downloaded the source and zipped it came in at
> ~800kb.

The BZip2 distro includes the manual in several different formats, e.g. a
1Mb PostScript file.

> Even if what you say is right, you are still comparing 100x more LOC.
> Only 730 loc? Seriously?

Sure. I won't contest that the C is far more verbose but this discussion was
solely about performance.

>> > We should note that it is only 100x slower than the high quality
>> > implementation, while the claim was that haskell would be 200x
>> > slower...
>>
>> No, the partially-implemented Haskell is already 100x slower that the
>> complete C implementation so a full Haskell implementation based upon it
>> must be over 100x slower.
> 
> That doesn't make sense. Adding code is not equal to adding extra run
> time. Sometimes adding code makes things faster, you know.

How could adding code that implements the subsequent phases of the
compression algorithm possibly decrease the total running time?

>> >> The poor performance of your Haskell code is a direct consequence of
>> >> Haskell's unpredictability. Obviously you failed to predict how bad
>> >> your code was or you would not have posted an example that contradicts
>> >> your own assertions.
>>
>> > He omits the fact that the poor performance is a result of not
>> > comparing apples to apples in any sort of reasonable manner.
>>
>> You misunderstood the comparison.
> 
> It seems it is a bad comparison....

Indeed, it turns out that Ertugrul's Haskell implementation is actually
broken.

>> > He also omits the fact that the author admited that it wasn't the
>> > highest quality implementation of zip compression.
>>
>> Ertugrul claimed he could write performant Haskell and then didn't.
> 
> I think he claimed it could be written, not that he was writing it.

Indeed, this is the second time he has made a claim about Haskell only to
prove himself wrong.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/12/2009 7:20:28 AM

Jon Harrop said:

> ACL wrote:
>> On Jul 10, 10:19 pm, wrote:
>>> ACL wrote:
>>> >> >> So either Haskell is not "decent" or 200x slower is "not
>>> >> >> considerably slower".
>>>
>>> > You see here, the wiley troll makes a claim of comparison as
>>> > if it is fact.
>>>
>>> Err, it is fact and I cited the source.
>> 
>> No you didn't. I just scrolled up. I see no study cited.
> 
> Here's that citation again:
> 
http://www.mail-archive.com/haskell-cafe%40haskell.org/msg25645.html

Hardly a "study" - just a single data point. Note that I don't doubt 
the claim. It is obvious to me that C++, being a bit of a 
cart-horse, is not going to manage to be much more than 200x faster 
than Haskell (which is more of a barge-horse, with a missing leg). 
Nevertheless, that single data point is only the tiniest indicator 
that this is so, and most certainly does not deserve to be 
dignified by the name of "study". To extrapolate an argument from a 
single datum is rarely wise.

<snip>

-- 
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
Forged article? See 
http://www.cpax.org.uk/prg/usenet/comp.lang.c/msgauth.php
"Usenet is a strange place" - dmr 29 July 1999
0
Reply rjh (10789) 7/12/2009 7:27:15 AM

On Jul 12, 8:40=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Raffael Cavallaro wrote:
> > On 2009-07-11 12:51:17 -0400, Nobody <nob...@nowhere.com> said:
> >> What imperative programmers seem to dislike is that monads take the
> >> fundamental nature of imperative languages and turn it into a "thing".
>
> > No, what programmers who haven't drunk the *pure*-functional kool aid
> > dislike about them is that they are just another form of unnecessary
> > boiler plate that gets in the way of simply stating directly what the
> > programmer wants to do.

They don't "get in the way" nearly as much as you think. But since
you know they are a bad idea (even without really understanding them),
I guess you will not spend your time learning about them (and thus
will
never understand them), and will continue complaining about them
instead.

> Indeed. We saw a nice example of that elsewhere on this very thread. Here=
 is
> a simple OCaml program that fills in an array by mutating elements in O(1=
):
>
> let bench n =3D
> =A0 let t =3D Sys.time() in
> =A0 ignore(Array.init n (fun i -> [i]));
> =A0 Printf.printf "%gs\n%!" ((Sys.time() -. t) *. 1e6 /. float n)
>
> let () =3D
> =A0 List.iter bench [10000; 100000; 1000000; 10000000]
>
> Here is the Haskell equivalent that fills in an STArray by mutating eleme=
nts
> in O(n):
[snip]

Here's another Haskell version. The benchmarking part is *untested*,
because I don't have StrictBench installed and am lazy, but it should
work. If not, the problem is some small typo; the general idea is
correct.

import Data.Array
import Data.Array.ST
import Test.StrictBench

mkArray :: Int -> Array Int [Int]
mkArray size =3D runSTArray $ do
   arr <- newArray (0, size - 1) []
   mapM_ (\i -> writeArray arr i [i]) [0 .. size - 1]
   return arr

main :: IO ()
main =3D mapM_ (bench . mkArray) [10^4, 10^5, 10^6, 10^7]

> The presence of monads raises many immediate questions:
>
> Why is this an STArray instead of an Array or STUArray or IOArray or
> IOUArray?

The U's stand for Unboxed, and you obviously don't want to talk
about them.

Array is immutable, STArray is a mutable array in the ST monad and
IOArray a mutable array in the IO monad. Using IO can be sometimes
convenient and easier for beginners, but most seem to prefer ST.

> Why must the programmer manually annotate the following type:
>
> =A0 ST s (STArray s Int [Int])
>
> when other languages with type inference (e.g. SML, OCaml, F#) do not
> require such type annotations?

This has nothing to do with monads. It's because newArray is
polymorphic,
and if you never use the array for anything, it's just not possible to
know which type of array you want.

> Why is "stToIO" needed?

Because the code is bad.

> The Haskell is far more verbose than the OCaml and uses many functions. I=
s
> this because each function requires a separate "do" because the imperativ=
e
> sections of code must be wrapped individually in monadic "do" notation?

No. The "do" notation is just syntactic sugar and is as composable
as all other kinds of expressions.

> How could I refactor this to use a more conventional "time" combinator?

Depends on the exact combinator. A function like mkArray above
is probably good.

> The answers to these questions are not at all obvious to me or, indeed, t=
o
> the vast majority of Haskell programmers who tinker with it without
> realising important facts like mutating an element in an array in O(n).

To not sound like a troll, I suggest not omitting the crucial fact
that it's O(n) for *boxed* arrays only. I have used mutable unboxed
arrays many times in Haskell (usually integers), but have never needed
boxed ones. I'm sure they have their uses and the bug in GHC is an
important one, but you *can* use arrays with O(1) mutation just as
you can in C.

--
Johannes Laire
0
Reply johannes.laire (2) 7/12/2009 10:36:23 AM

On Fri, 10 Jul 2009 16:12:08 -0400, Raffael Cavallaro
<raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> wrote: 
> On 2009-07-10 14:55:48 -0400, Larry D'Anna <larry@elder-gods.org> said:
>
>> You just have to use monads to get to it all.  You
>> can take any imperative algorithm you like and translate it into Haskell in a
>> totally straightforward way.
>
> monads. straightforward. <= contradiction in terms

The thing is you don't have to understand monads to use them.  If you
just use the do-syntax you can use the monad model as an abstraction
and not worry about the model itself.

0
Reply dformosa1 (36) 7/12/2009 10:59:56 AM

Jon Harrop <jon@ffconsultancy.com> schrieb:
> ... a programmer who does not understand
> monads cannot even hope to accomplish the simplest of tasks.

You're absolutely right.

0
Reply me4 (18695) 7/12/2009 5:14:39 PM

David Formosa (aka ? the Platypus) wrote:
> On Fri, 10 Jul 2009 16:12:08 -0400, Raffael Cavallaro
> <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> wrote:
>> On 2009-07-10 14:55:48 -0400, Larry D'Anna <larry@elder-gods.org> said:
>>
>>> You just have to use monads to get to it all.  You
>>> can take any imperative algorithm you like and translate it into Haskell
>>> in a totally straightforward way.
>>
>> monads. straightforward. <= contradiction in terms
> 
> The thing is you don't have to understand monads to use them.  If you
> just use the do-syntax you can use the monad model as an abstraction
> and not worry about the model itself.

You cannot answer the questions I asked about the array benchmark code in
Haskell without explaining monads. So a programmer who does not understand
monads cannot even hope to accomplish the simplest of tasks.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/12/2009 6:08:45 PM

Johannes Laire wrote:
> Here's another Haskell version. The benchmarking part is *untested*,
> because I don't have StrictBench installed and am lazy, but it should
> work. If not, the problem is some small typo; the general idea is
> correct.
> 
> import Data.Array
> import Data.Array.ST
> import Test.StrictBench
> 
> mkArray :: Int -> Array Int [Int]
> mkArray size = runSTArray $ do
>    arr <- newArray (0, size - 1) []
>    mapM_ (\i -> writeArray arr i [i]) [0 .. size - 1]
>    return arr
> 
> main :: IO ()
> main = mapM_ (bench . mkArray) [10^4, 10^5, 10^6, 10^7]

Thanks. That looks much nicer.

>> The presence of monads raises many immediate questions:
>>
>> Why is this an STArray instead of an Array or STUArray or IOArray or
>> IOUArray?
> 
> The U's stand for Unboxed, and you obviously don't want to talk
> about them.

Given the information you provide below, surely it is essential to talk
about them?

> To not sound like a troll, I suggest not omitting the crucial fact
> that it's O(n) for *boxed* arrays only.

What exactly does that mean? Will an STArray of Int be unboxed and O(1)
write? Can an STUArray of Lists exist?

> I have used mutable unboxed 
> arrays many times in Haskell (usually integers), but have never needed
> boxed ones. I'm sure they have their uses...

Most fast dictionary implementations are built upon arrays of boxed types,
such as hash tables.

> and the bug in GHC is an 
> important one, but you *can* use arrays with O(1) mutation just as
> you can in C.

In C I can write a list into an array in O(1). Is that possible with
Haskell?

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/12/2009 6:52:51 PM

On 2009-07-12 00:32:01 -0400, Paul Rubin <http://phr.cx@NOSPAM.invalid> said:

> I could say that traditional effectful computation, in whatever
> language, is already done in a monad.

You could certainly say it, but it wouldn't be true. Your claim is 
rather like saying that everyone who has a traditional Thanksgiving 
dinner really craves Tofurky. Haskell is forced to make "effectful 
computation" an explicit monad because, having denied itself side 
effects, it had to add them back to the language so it could do useful 
things. In a "tradtional effectful" language, these obviously useful 
features were never eschewed in the first place, so there was no need 
to jump through category theory hoops to get them back.


That pure functional languages conceptualize side effects as monads is 
just reflection of their narrow view of computation, not a reflection 
of the inherent nature of side effects. It is perfectly legitimate (in 
fact, it is the human cognitive norm) to conceptualize the world as 
inherently stateful and constantly mutating. You only reach for monads 
when you insist that the world (or all computation) is a set of 
functions returning values.



-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/13/2009 4:48:49 AM

On 2009-07-12 06:36:23 -0400, Johannes Laire <johannes.laire@gmail.com> said:

> On Jul 12, 8:40�am, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Raffael Cavallaro wrote:
>>> On 2009-07-11 12:51:17 -0400, Nobody <nob...@nowhere.com> said:
>>>> What imperative programmers seem to dislike is that monads take the
>>>> fundamental nature of imperative languages and turn it into a "thing".
>> 
>>> No, what programmers who haven't drunk the *pure*-functional kool aid
>>> dislike about them is that they are just another form of unnecessary
>>> boiler plate that gets in the way of simply stating directly what the
>>> programmer wants to do.
> 
> They don't "get in the way" nearly as much as you think. But since
> you know they are a bad idea (even without really understanding them),
> I guess you will not spend your time learning about them (and thus
> will
> never understand them), and will continue complaining about them
> instead.

Jon didn't write the part you're responding to here, I did.

It's condescending and inaccurate to claim that I don't understand 
monads. I just disagree with you regarding their utility. I think that 
programming idioms should leverage human cognitive strenghts, not 
require the programmer to completely recast the world according to the 
paradigm of the programming language.

The benefits of functional programming are well known, particularly in 
this forum. But it does not follow that because a thing is beneficial 
that it should be applied universally. In particular, one can tell when 
a metaphor is being overextended, when a paradigm is pushed beyond it's 
utility, when it requires that practitioners discard their natural 
cognitive strengths and wholly reconceptualize the world. *Pure* 
functional programming is such an overextended metaphor, and monads are 
symptomatic.
-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/13/2009 5:06:52 AM

On Jul 13, 6:48=A0am, Raffael Cavallaro wrote:
>
> That pure functional languages conceptualize side effects as monads is
> just reflection of their narrow view of computation, not a reflection
> of the inherent nature of side effects. It is perfectly legitimate (in
> fact, it is the human cognitive norm) to conceptualize the world as
> inherently stateful and constantly mutating.

People used to conceptualize numbers by using their fingers. Do you
think modern math would have evolved that way? Is set theory or are
the Peano axioms a narrow view of numbers because they eschew fingers?

> You only reach for monads
> when you insist that the world (or all computation) is a set of
> functions returning values.

Try talking to a quantum physicist about the world not being a set of
functions. ;-)
0
Reply rossberg1 (19) 7/13/2009 7:21:37 AM

On 2009-07-13 03:21:37 -0400, Andreas Rossberg <rossberg@mpi-sws.org> said:

> People used to conceptualize numbers by using their fingers.

This is false. Many higher animals have an innate sense of number, 
including some who don't even have digits. You're simply repeating a 
folk fallacy here.

> Do you
> think modern math would have evolved that way? Is set theory or are
> the Peano axioms a narrow view of numbers because they eschew fingers?
> 
>> You only reach for monads
>> when you insist that the world (or all computation) is a set of
>> functions returning values.
> 
> Try talking to a quantum physicist about the world not being a set of
> functions. ;-)

Which is tantamount to saying that to be a programmer, one must fully 
understand quantum physics. Thank you for providing the reductio ad 
absurdum of your own argument for me.

The issue isn't whether the universe is "really" functional or not. The 
issue is that programming languages are *not* an interface between 
hardware and the intrinsic nature of the universe. Programming 
languages are an interface between hardware and human cognitive 
abilities. As such they should leverage native human cognitive 
abilities, not physicists' most recent, and ever-changing estimate of 
the intrinsic nature of the universe, nor any other paradigm that is at 
odds with the way people most easily conceptualize a particular problem 
domain.

IOW, don't force people to change the way they think best in order to 
program; mold programming languages to fit the way people think best.


-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/13/2009 1:04:40 PM

On Jul 13, 3:04=A0pm, Raffael Cavallaro
<raffaelcavall...@pas.espam.s.il.vous.plait.mac.com> wrote:
> > People used to conceptualize numbers by using their fingers.
>
> This is false. Many higher animals have an innate sense of number,
> including some who don't even have digits.

I don't see how that falsifies what I said. But anyway, the point was:
hardware and software are highly complex artefacts -- with a degree of
complexity far beyond what people usually cope with. Appealing to how
these people "normally" "conceptualize" things, or worse, summoning
the mythical "Real World", is useless when it comes to finding the
best ways of dealing with this complexity.

> >> You only reach for monads
> >> when you insist that the world (or all computation) is a set of
> >> functions returning values.
>
> > Try talking to a quantum physicist about the world not being a set of
> > functions. ;-)
>
> Which is tantamount to saying that to be a programmer, one must fully
> understand quantum physics. Thank you for providing the reductio ad
> absurdum of your own argument for me.

It is just saying that you should be careful with drawing conclusions
from what you percept as "reality". And you didn't quite notice the
smiley.

- Andreas
0
Reply rossberg1 (19) 7/13/2009 2:07:53 PM

On 2009-07-13 10:07:53 -0400, Andreas Rossberg <rossberg@mpi-sws.org> said:

> On Jul 13, 3:04�pm, Raffael Cavallaro
> <raffaelcavall...@pas.espam.s.il.vous.plait.mac.com> wrote:
>>> People used to conceptualize numbers by using their fingers.
>> 
>> This is false. Many higher animals have an innate sense of number,
>> including some who don't even have digits.
> 
> I don't see how that falsifies what I said.

Because fingers are a mnemonic device, not how numbers are 
conceptualized. Does using a laptop mean that I conceptualize numbers 
as backlit liquid crystals? Does using arabic numerals mean that I 
conceptualize the number three as two stacked semi-circles open on the 
left? Hardly.

> But anyway, the point was:
> hardware and software are highly complex artefacts -- with a degree of
> complexity far beyond what people usually cope with. Appealing to how
> these people "normally" "conceptualize" things, or worse, summoning
> the mythical "Real World", is useless when it comes to finding the
> best ways of dealing with this complexity.

Again, I'm not the one appealing to notions of the "real world," you 
are. I'm appealing to notions of native cognitive skills. Whether or 
not our native cognitive abilites ultimately correspond to "reality" is 
a question for philosophers[1], and ultimately largely irrelevant to 
leveraging the tools we've been handed by evolution and millenia of 
cultural development.

We shouldn't discard native cognitive abilities merely because one 
paradigm (functional) has proven extremely useful in a particular 
domain (mathematics) and attempt to shoehorn all computation into that 
functional model. *Pure* functional programming falls into the trap of 
thinking that because a paradigm is useful in many circumstances, it 
should be universal. In doing so we discard cognitive abilities that 
human beings are excellent at, and which we've been honing for at least 
tens of thousands of years. Specifically, the ability to keep track of 
the intersecting timelines of numerous, constantly mutating, stateful 
entities.

> 
>>>> You only reach for monads
>>>> when you insist that the world (or all computation) is a set of
>>>> functions returning values.
>> 
>>> Try talking to a quantum physicist about the world not being a set of
>>> functions. ;-)
>> 
>> Which is tantamount to saying that to be a programmer, one must fully
>> understand quantum physics. Thank you for providing the reductio ad
>> absurdum of your own argument for me.
> 
> It is just saying that you should be careful with drawing conclusions
> from what you percept as "reality". And you didn't quite notice the
> smiley.

Again I'm not the one appealing to some ultimate "reality," you are. I 
make no claims that native human cognitive abilities correspond to some 
ultimate "reality." I merely claim that they are powerful tools that we 
discard to our loss.



[1] Yes, philosophers, not physicists. The claim that our current best 
physical model of the universe corresponds to some underlying ultimate 
reality is a metaphysical claim, not a scientific one. Science itself 
is mute on this point.
-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/13/2009 3:18:25 PM

Andreas Rossberg wrote:
> On Jul 13, 6:48 am, Raffael Cavallaro wrote:
>>
>> That pure functional languages conceptualize side effects as monads is
>> just reflection of their narrow view of computation, not a reflection
>> of the inherent nature of side effects. It is perfectly legitimate (in
>> fact, it is the human cognitive norm) to conceptualize the world as
>> inherently stateful and constantly mutating.
> 
> People used to conceptualize numbers by using their fingers. Do you
> think modern math would have evolved that way? Is set theory or are
> the Peano axioms a narrow view of numbers because they eschew fingers?

Side effects are essential in programming but fingers are not in
mathematics. So how is that analogous?

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/13/2009 5:17:07 PM

On Mon, 13 Jul 2009 00:48:49 -0400, Raffael Cavallaro wrote:

> That pure functional languages conceptualize side effects as monads is 
> just reflection of their narrow view of computation,

You have it backwards. The fact that imperative languages assume
statefulness as a given is a reflection of their narrow view of
computation.

IMHO, imperative programmers don't like Haskell's Monad class because it
takes what is fundamental to imperative languages and turns it into a
"thing". And such a small thing at that.

I can't think of any other reason why this subject seems to provoke such
hostility from people with an imperative mind-set.

> not a reflection 
> of the inherent nature of side effects. It is perfectly legitimate (in 
> fact, it is the human cognitive norm) to conceptualize the world as 
> inherently stateful and constantly mutating.

You have a choice in how you conceptualise the world. I don't think the
Church-Turing thesis is news to anyone here.

The question isn't about which model is "legitimate", but which is a good
idea.

As for "human cognitive norms", there's often a big difference between
perception and reality, and you generally get better results if you deal
with the latter.

0
Reply nobody (4804) 7/13/2009 6:35:08 PM

Jon Harrop <jon@ffconsultancy.com> wrote:

> >>>> The poor performance of your Haskell code is a direct consequence
> >>>> of Haskell's unpredictability. Obviously you failed to predict
> >>>> how bad your code was or you would not have posted an example
> >>>> that contradicts your own assertions.
> >>>
> >>> He omits the fact that the poor performance is a result of not
> >>> comparing apples to apples in any sort of reasonable manner.
> >>
> >> You misunderstood the comparison.
> >
> > It seems it is a bad comparison....
>
> Indeed, it turns out that Ertugrul's Haskell implementation is
> actually broken.

Its output is shifted compared to the original BWT transform.  You can
correct that without adding extra code, although there is no reason to
do that.  And I say it again:  Replace the list sorting by an in-place
sort and you get orders of magnitude better performance.  I was just too
lazy to implement it.


> >>> He also omits the fact that the author admited that it wasn't the
> >>> highest quality implementation of zip compression.
> >>
> >> Ertugrul claimed he could write performant Haskell and then didn't.
> >
> > I think he claimed it could be written, not that he was writing it.
>
> Indeed, this is the second time he has made a claim about Haskell only
> to prove himself wrong.

This is about the hundredth time you claim that I have proven myself
wrong.  You said that the best Haskell implementation some people from
the ML could come up with was 200 times slower than equivalent C code.
I wrote in a matter of 10 minutes a (nowhere near optimal) variant,
which is, according to you, only 100 times slower.  I disregard the fact
that you have repeatedly shown that you're unable to use the compiler
properly.  Anyway, the bad performance comes from the fact that I have
used list sorting.  See above for how to fix this.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/13/2009 7:12:33 PM

Ertugrul S�ylemez <es@ertes.de> writes:
> Replace the list sorting by an in-place sort and you get orders of
> magnitude better performance.  I was just too lazy to implement it.

I wonder if the sorting code in uvector could handle it.

http://hackage.haskell.org/package/uvector-algorithms
0
Reply phr.cx (5483) 7/13/2009 7:28:12 PM

Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> wrote:

> > I could say that traditional effectful computation, in whatever
> > language, is already done in a monad.
>
> You could certainly say it, but it wouldn't be true. Your claim is
> rather like saying that everyone who has a traditional Thanksgiving
> dinner really craves Tofurky. Haskell is forced to make "effectful
> computation" an explicit monad because, having denied itself side
> effects, it had to add them back to the language so it could do useful
> things. In a "tradtional effectful" language, these obviously useful
> features were never eschewed in the first place, so there was no need
> to jump through category theory hoops to get them back.
>
> That pure functional languages conceptualize side effects as monads is
> just reflection of their narrow view of computation, not a reflection
> of the inherent nature of side effects. It is perfectly legitimate (in
> fact, it is the human cognitive norm) to conceptualize the world as
> inherently stateful and constantly mutating. You only reach for monads
> when you insist that the world (or all computation) is a set of
> functions returning values.

People love to use metaphors in such discussions.  I doubt that it's
useful in any way.  Let's discuss facts instead.

Firstly monads are not an indirection.  Expressing side effects or state
monadically could hardly be any more direct.  You have state, you can
'get' it, use it, 'modify' it and/or 'put' it back.  The same with IO,
just that you have no 'get' function, because the state of the universe
has no distinct value in memory.  Instead you have a bunch of functions
like 'putStr', 'hGetLine', 'connect', etc., which modify the universe
state.

What's wrong with this?  It's not more to type than in C, in fact it's
less to type in most cases and even more intuitive to read.  What could
be more intuitive than

  forever (putStrLn "Hello world!")

for an endless loop printing a line repeatedly?  It's just that people
who don't like monads either never used them (properly) or never made
efforts to understand them.  Evidence for this comes from the frequent
but wrong claim that monads are there to "bring back" effectful
computation.  Monads are universal tools for many things and show their
true power, as soon as you start combining them through monad
transformers.

However, this post is probably pointless anyway.  Most people on Usenet
are totally obstinate.  I recommend you to try out Haskell for more than
an hour.  After all I was a convinced C programmer a few years ago, so
it's not that I'm so fond of Haskell because it's the only thing I know.
And that's about all I can say at this point.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/13/2009 8:12:10 PM

Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> wrote:

> > You may want to show me something that couldn't be implemented in
> > Haskell, or where the additional safety gets in your way.
>
> "couldn't be implemented" is a turing tarpit red herring. For "gets in
> your way," upthread we've just been discussing the pointless need to
> use monads just to get simple mutable state.

You still failed to show how this is "pointless".  It's not even a
"need", as there are many other ways to handle side effects in a purely
functional language.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/13/2009 8:13:45 PM

Jon Harrop <jon@ffconsultancy.com> wrote:

> > You may want to show me something that couldn't be implemented in
> > Haskell, or where the additional safety gets in your way.
>
> A Haskell implementation of the BWT sort that gets within 2x the
> performance of C.

I'll consider it when I have some time. =)


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/13/2009 8:14:58 PM

Jon Harrop <jon@ffconsultancy.com> wrote:

> > Its output is shifted compared to the original BWT transform.  You
> > can correct that without adding extra code, although there is no
> > reason to do that.  And I say it again:  Replace the list sorting by
> > an in-place sort and you get orders of magnitude better performance.
> > I was just too lazy to implement it.
>
> Put up or shut up, Ertugrul. Its as simple as that. Show us the
> Haskell implementation that gives the correct answer and is "not
> considerably slower" than the C or retract your claim. Your choice.

Unfortunately I don't have the time to prove my claims all the time,
just because some hair splitter like you insists on it.  But as said in
another subthread, I'll consider it.

If you're impatient, you may want to pay me for doing it.


Greets,
Ertugrul.


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://blog.ertes.de/

0
Reply es1 (159) 7/13/2009 8:44:33 PM

On 2009-07-11, Jon Harrop <jon@ffconsultancy.com> wrote:
> Larry D'Anna wrote:
>> On 2009-07-11, Johannes Laire <johannes.laire@gmail.com> wrote:
>>> Jon Harrop wrote:
>>>> Larry D'Anna wrote:
>>>> > ["Followup-To:" header set to comp.lang.lisp.]
>>>> > On 2009-07-10, Jon Harrop <j...@ffconsultancy.com> wrote:
>>>> >> Here is a trivial counter example: mutate an element in an array in
>>>> >> O(1).
>>>>
>>>> > easy.
>>>>
>>>> >http://cvs.haskell.org/Hugs/pages/libraries/base/Data-Array-ST.html
>>>>
>>>> That is O(n) with GHC.
>>>
>>> It is O(1) for unboxed arrays.
>> 
>> I thought it was O(1) for boxed arrays too, but I tested it and defiantly
>> is not.  Any idea why boxed vs. unboxed should make a difference?
>
> The write barrier incurred when mutating a boxed element in an array dirties
> the whole array and that causes the GC to traverse the whole array at every
> minor/gen0 GC, which is periodic (separated by constant amounts of time for
> the purposes of this description). That dirtying is not necessary for
> unboxed elements so you do not see the asymptotic performance degradation
> with them, e.g. the STUArray of Int in your example.

Why in the world does it have to dirty the whole array?  Is there any sane
reason for that or is this just an unfortunate deficiency of GHC?  I just can't
believe that an array update is O(n).  But but my tests updating a STArray
really is O(n) in GHC.  I'm a bit shocked.

          --larry
0
Reply larry4779 (10) 7/13/2009 8:58:07 PM

On Jul 13, 2:30=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Ertugrul S=F6ylemez wrote:
> > Jon Harrop <j...@ffconsultancy.com> wrote:
> >> > You may want to show me something that couldn't be implemented in
> >> > Haskell, or where the additional safety gets in your way.
>
> >> A Haskell implementation of the BWT sort that gets within 2x the
> >> performance of C.
>
> > I'll consider it when I have some time. =3D)
>
> So decent functional languages are only competitively performant after
> infinite development time?

Oh good grief.  You really think the C version was written in an
hour??  And you think Ertugrul doesn't have better things to do than
argue on Usenet?

Really, Jon, for a smart guy you say some amazingly stupid things
sometimes.

-- Scott
0
Reply FSet.SLB (346) 7/13/2009 8:58:50 PM

On 2009-07-11, Jon Harrop <jon@ffconsultancy.com> wrote:
> Fill the array with the list [i] instead of the integer i and you get:
>
> 0
> 240010
> 552034
> 3161398
>
> That is clearly not O(1).

Wow you're right.  Only the unboxed arrays are O(1).  I'm a bit shocked.

    --larry
0
Reply larry4779 (10) 7/13/2009 9:00:34 PM

Ertugrul Söylemez wrote:
> Its output is shifted compared to the original BWT transform.  You can
> correct that without adding extra code, although there is no reason to
> do that.  And I say it again:  Replace the list sorting by an in-place
> sort and you get orders of magnitude better performance.  I was just too
> lazy to implement it.

Put up or shut up, Ertugrul. Its as simple as that. Show us the Haskell
implementation that gives the correct answer and is "not considerably
slower" than the C or retract your claim. Your choice.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/13/2009 9:28:41 PM

Ertugrul Söylemez wrote:
> Jon Harrop <jon@ffconsultancy.com> wrote:
>> > You may want to show me something that couldn't be implemented in
>> > Haskell, or where the additional safety gets in your way.
>>
>> A Haskell implementation of the BWT sort that gets within 2x the
>> performance of C.
> 
> I'll consider it when I have some time. =)

So decent functional languages are only competitively performant after
infinite development time?

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/13/2009 9:30:51 PM

On 2009-07-12, Raffael Cavallaro wrote:

> No, what programmers who haven't drunk the *pure*-functional kool aid 
> dislike about them is that they are just another form of unnecessary 
> boiler plate that gets in the way of simply stating directly what the 
> programmer wants to do. 

Do you really imagine monads serve no useful purpose whatsoever, and that Simon
Peyton-Jones is just too stupid too see how worthless they are?  Or maybe, is it
possible that there's something you've missed, that there are certain things
that monads enable that aren't possible without them.

Let me give you a few hints

Let's say you're writing a search engine.  What type of text file is easier to
handle: plain text, or postscript?

which java function would you rather call:
   public void fooBar() {...
OR public void fooBar() throws Exception {...

All else being equal, which Haskell function would you rather use:

    foo :: a -> b
OR  bar :: a -> IO b

Do you get it yet?

http://en.wikipedia.org/wiki/Principle_of_Least_Power

Monads let the programmer specify which functions are pure functional, and which
ones are not.  In fact, they let the programmer specify with fine granularity
what sort of side effects each function might produce.  If you want "anything
goes" you use IO.  If you want mutable references and arrays you use MArray.  If
you want continuations you can use MonadCont.  And with the magic of typeclasses
and monad transformers, you can mix and match to get a monad that has exactly
the combination of functionality you need and no more.

You may still say "monad aren't worth the trouble".  But least now you won't go
around idiotically saying things are worthless without having a clue what
they're for.
0
Reply larry4779 (10) 7/13/2009 9:48:03 PM

On 2009-07-12, Jon Harrop <jon@ffconsultancy.com> wrote:
> Raffael Cavallaro wrote:
>> On 2009-07-11 12:51:17 -0400, Nobody <nobody@nowhere.com> said:
>>> What imperative programmers seem to dislike is that monads take the
>>> fundamental nature of imperative languages and turn it into a "thing".
>> 
>> No, what programmers who haven't drunk the *pure*-functional kool aid
>> dislike about them is that they are just another form of unnecessary
>> boiler plate that gets in the way of simply stating directly what the
>> programmer wants to do.
>
> Indeed. We saw a nice example of that elsewhere on this very thread. Here is
> a simple OCaml program that fills in an array by mutating elements in O(1):
>
> let bench n =
>   let t = Sys.time() in
>   ignore(Array.init n (fun i -> [i]));
>   Printf.printf "%gs\n%!" ((Sys.time() -. t) *. 1e6 /. float n)
>
> let () =
>   List.iter bench [10000; 100000; 1000000; 10000000]
>
> Here is the Haskell equivalent that fills in an STArray by mutating elements
> in O(n):

[ large, inelegant program deleted ]

It's really not fair to take my Haskell code as an example of Haskell's
verbosity.  That's probably the longest Haskell program I've written.  I'm no
Haskell expert.  

            --larry
0
Reply larry4779 (10) 7/13/2009 9:53:23 PM

On Mon, 13 Jul 2009 22:44:33 +0200, Ertugrul
=?UTF-8?B?U8O2eWxlbWV6?= <es@ertes.de> wrote:

>Jon Harrop <jon@ffconsultancy.com> wrote:
>
>> > Its output is shifted compared to the original BWT transform.  You
>> > can correct that without adding extra code, although there is no
>> > reason to do that.  And I say it again:  Replace the list sorting by
>> > an in-place sort and you get orders of magnitude better performance.
>> > I was just too lazy to implement it.
>>
>> Put up or shut up, Ertugrul. Its as simple as that. Show us the
>> Haskell implementation that gives the correct answer and is "not
>> considerably slower" than the C or retract your claim. Your choice.
>
>Unfortunately I don't have the time to prove my claims all the time,
>just because some hair splitter like you insists on it.  But as said in
>another subthread, I'll consider it.
>
>If you're impatient, you may want to pay me for doing it.

While we all sympathize with the limits on your time, it remains
that you made a major claim about the efficiency of Haskell that
remains unsubstantiated.


Richard Harter, cri@tiac.net
http://home.tiac.net/~cri, http://www.varinoma.com
If I do not see as far as others, it is because
I stand in the footprints of giants. 
0
Reply cri (1432) 7/13/2009 9:53:52 PM

cri@tiac.net (Richard Harter) writes:
> While we all sympathize with the limits on your time, it remains
> that you made a major claim about the efficiency of Haskell that
> remains unsubstantiated.

The Alioth shootout results are reasonable substantiation for general
claims about Haskell performance.  Jon's specific challenge is pretty
worthless unless he can put up Ocaml or F# code that has the
performance that he's demanding from Ertagul's Haskell code.
0
Reply phr.cx (5483) 7/13/2009 10:06:03 PM

Raffael Cavallaro <raffaelcavallaro@pas.espam.s.il.vous.plait.mac.com> writes:
> > I could say that traditional effectful computation, in whatever
> > language, is already done in a monad.
> 
> You could certainly say it, but it wouldn't be true.

You can certainly say it is false, but it is true anyway ;-).
Take a look at Harpy for example--an embedded assembler in which
every machine instruction is a monad action.

> It is perfectly legitimate (in fact, it is the human cognitive norm)
> to conceptualize the world as inherently stateful and constantly
> mutating.

The human cognitive norm is full of errors and inconsistencies (look
at the problems of concurrent programming for example).  Writing sound
code is most easily done using models with sound mathematical
properties.  Human cognition doesn't have those properties, but monads
do just fine.

Have you actually done any programming in Haskell?  Like most
languages, Haskell has many characteristics that are inconvenient or
confusing.  Modelling effectul computations as monad actions is fairly
far down on the list.
0
Reply phr.cx (5483) 7/13/2009 10:39:55 PM

On Jul 13, 2:53=A0pm, c...@tiac.net (Richard Harter) wrote:
>
> While we all sympathize with the limits on your time, it remains
> that you made a major claim about the efficiency of Haskell that
> remains unsubstantiated.

I'm curious about the outcome too, but whether Ertugrul can come
within a factor of 2 of the C implementation is, to me, not the most
interesting question.  I'd be more interested to know the ratio of the
time it takes him to the time the C implementation took to write.  It
seems unlikely, though, that the latter number can be obtained.

-- Scott
0
Reply FSet.SLB (346) 7/14/2009 12:15:46 AM

[Cross-posting trimmed to groups I read...]

Larry D'Anna  <larry@elder-gods.org> wrote:
+---------------
| Jon Harrop <jon@ffconsultancy.com> wrote:
| > Larry D'Anna wrote:
| >> Johannes Laire <johannes.laire@gmail.com> wrote:
| >>>> That is O(n) with GHC.
| >>>
| >>> It is O(1) for unboxed arrays.
| >> 
| >> I thought it was O(1) for boxed arrays too, but I tested it and defiantly
| >> is not.  Any idea why boxed vs. unboxed should make a difference?
| >
| > The write barrier incurred when mutating a boxed element in an array dirties
| > the whole array and that causes the GC to traverse the whole array at every
| > minor/gen0 GC, which is periodic (separated by constant amounts of time for
| > the purposes of this description). That dirtying is not necessary for
| > unboxed elements so you do not see the asymptotic performance degradation
| > with them, e.g. the STUArray of Int in your example.
| 
| Why in the world does it have to dirty the whole array?  Is there any sane
| reason for that or is this just an unfortunate deficiency of GHC?  I just
| can't believe that an array update is O(n).  But but my tests updating a
| STArray really is O(n) in GHC.  I'm a bit shocked.
+---------------

If GHC were using a generational GC with a software card-marking
write barrier, then updating a single element in an array of boxed
elements should at most dirty a card's worth of elements. According
papers I've read on this, good "card" sizes these days are ~256 bytes
[or at least somewhere in the 128-1024 byte range], which on a 32-bit
machine would mean an extra 64 elements to scan during the first GC
following the update [but possibly no extra work thereafter, if the
updated value gets promoted into the same generation as the array].
This would therefore be an O(1) cost w.r.t. to the size of the array,
though O(c) for "c" the number of distinct cards updated. [That is,
doing a zillion updates to all of the elements of one card costs
no more GC overhead than doing a single update to that same card.]

So all you're saying is that GHC isn't using that kind of GC.  ;-}


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607

0
Reply rpw3 (2294) 7/14/2009 12:41:45 AM

Scott Burson <FSet.SLB@gmail.com> writes:
> I'd be more interested to know the ratio of the time it takes him to
> the time the C implementation took to write.  It seems unlikely,
> though, that the latter number can be obtained.

This might be of interest:

  http://www.cse.iitb.ac.in/~as/fpcourse/jfp.ps

See the chart on page 9.
0
Reply phr.cx (5483) 7/14/2009 12:55:59 AM

* Larry D'Anna <h3ga2j$297$1@news.eternal-september.org> :
Wrote on Mon, 13 Jul 2009 21:48:03 +0000 (UTC):

| On 2009-07-12, Raffael Cavallaro wrote:
|
|> No, what programmers who haven't drunk the *pure*-functional kool aid 
|> dislike about them is that they are just another form of unnecessary 
|> boiler plate that gets in the way of simply stating directly what the 
|> programmer wants to do. 
|
| Do you really imagine monads serve no useful purpose whatsoever, and
| that Simon Peyton-Jones is just too stupid too see how worthless they
| are?  Or maybe, is it possible that there's something you've missed,
| that there are certain things that monads enable that aren't possible
| without them.

The thing to consider is whether Simon Peyton-Jones is just too clever
in pulling off what he has done, and has been successfully distracting
the developer community from producing serious competition by limiting
"empowering technologies"

--
Madhu
0
Reply enometh (820) 7/14/2009 2:35:26 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> Ertugrul found plenty of time to post these baseless claims but, now that
> I'm calling his bluff, he cannot find the time to optimize his 6-line
> function. Sounds fishy to me...

By your logic, you should also admit that F# and Ocaml are also
worthlessly slow, until you can optimize that same function to the
level you have requested from Ertugrul.  Go on, admit it, or put up.
We're waiting.
0
Reply phr.cx (5483) 7/14/2009 2:42:14 AM

On Jul 13, 8:46=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Scott Burson wrote:
> > And you think Ertugrul doesn't have better things to do than
> > argue on Usenet?
>
> Ertugrul found plenty of time to post these baseless claims but, now that
> I'm calling his bluff, he cannot find the time to optimize his 6-line
> function. Sounds fishy to me...

Haskell is a pretty good language for prototyping though, as I think
anyone preferring static typing will agree.
0
Reply fft1976 (100) 7/14/2009 2:43:27 AM

On Jul 13, 9:06=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> fft1976 wrote:
> > On Jul 13, 8:46=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> >> Scott Burson wrote:
> >> > And you think Ertugrul doesn't have better things to do than
> >> > argue on Usenet?
>
> >> Ertugrul found plenty of time to post these baseless claims but, now t=
hat
> >> I'm calling his bluff, he cannot find the time to optimize his 6-line
> >> function. Sounds fishy to me...
>
> > Haskell is a pretty good language for prototyping though, as I think
> > anyone preferring static typing will agree.
>
> No, I would not agree. OCaml's type inference puts Haskell to shame and i=
s
> maximally beneficial during prototyping. Indeed, OCaml's inferred
> structural types (polymorphic variants and objects) are the only features
> that have closed the gap between static and dynamic typing for me, to the
> extent that I no longer use dynamic languages at all.
>
> They are also the features I miss the most in F#.

The goal of prototyping, for me, is getting at some conceptual
clarity, which polymorphic variants, due to their wicked power, just
don't give me.

0
Reply fft1976 (100) 7/14/2009 3:08:49 AM

Scott Burson wrote:
> And you think Ertugrul doesn't have better things to do than 
> argue on Usenet?

Ertugrul found plenty of time to post these baseless claims but, now that
I'm calling his bluff, he cannot find the time to optimize his 6-line
function. Sounds fishy to me...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 3:46:43 AM

Larry D'Anna wrote:
> Why in the world does it have to dirty the whole array?  Is there any sane
> reason for that or is this just an unfortunate deficiency of GHC?

Of course there is a sane reason! The *only* way you can justify the
following claim is by crippling your hash table implementation:

  "Compared to a hash table, a well-implemented purely functional tree data
structure will perform competitively. You should not approach trees with
the assumption that your code will pay a performance penalty." - Real World
Haskell

Had they done a decent job implementing imperative constructs in GHC, their
impure hash table implementation would thrash all purely functional tree
implementations (just as the hash table implementations in decent languages
like OCaml and F# do). That would make purely functional programming look
like a really bad idea so they had to "work around" the problem and
O(n^2) "hash tables" are the perfect hoax.

I'm being facetious, of course. I suspect the real reason is not conspiracy
but incompetence. Whoever wrote that nonsense in Real World Haskell hadn't
done their homework properly. I bet they just benchmarked hash tables vs
trees using GHC and concluded that trees were much faster without doing any
objective tests with other languages. After all, decent benchmarking is
hardcore science.

Anyway, these long-standing performance bugs in the GHC run-time are the
least of your worries. Wait until you get on to the memory leaks in the
run-time...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 3:59:19 AM

Larry D'Anna wrote:
> It's really not fair to take my Haskell code as an example of Haskell's
> verbosity.  That's probably the longest Haskell program I've written.  I'm
> no Haskell expert.

Sorry, I retract my verbosity comparison.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 4:01:16 AM

fft1976 wrote:
> On Jul 13, 8:46 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Scott Burson wrote:
>> > And you think Ertugrul doesn't have better things to do than
>> > argue on Usenet?
>>
>> Ertugrul found plenty of time to post these baseless claims but, now that
>> I'm calling his bluff, he cannot find the time to optimize his 6-line
>> function. Sounds fishy to me...
> 
> Haskell is a pretty good language for prototyping though, as I think
> anyone preferring static typing will agree.

No, I would not agree. OCaml's type inference puts Haskell to shame and is
maximally beneficial during prototyping. Indeed, OCaml's inferred
structural types (polymorphic variants and objects) are the only features
that have closed the gap between static and dynamic typing for me, to the
extent that I no longer use dynamic languages at all.

They are also the features I miss the most in F#.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 4:06:30 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> First up, here are my timings for encoding a 5.5Mb copy of the bible:
> pbzip2:             ~1.0s
> bzip2:              ~1.5s
> My F#:               1.4s

Nice job!  However, how much of your time did you spend writing that
code, just to prove something that you already knew?
 
> FWIW, I'm happy to spend time on interesting projects like this because I
> can turn them into OCaml and F#.NET Journal articles. :-)

Since Ertugrul isn't in the journal article business, perhaps his
suggestion of having you offer to pay him to write code would be a
workable alternative motivation.

Here is another interesting Haskell vs. C benchmark:

  http://augustss.blogspot.com/2009/02/is-haskell-fast-lets-do-simple.html

;-) 
0
Reply phr.cx (5483) 7/14/2009 4:32:38 AM

Paul Rubin wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> Ertugrul found plenty of time to post these baseless claims but, now that
>> I'm calling his bluff, he cannot find the time to optimize his 6-line
>> function. Sounds fishy to me...
> 
> By your logic, you should also admit that F# and Ocaml are also
> worthlessly slow, until you can optimize that same function to the
> level you have requested from Ertugrul.  Go on, admit it, or put up.
> We're waiting.

I didn't come here for a fight but that doesn't mean I won't kick your
ass. ;-)

First up, here are my timings for encoding a 5.5Mb copy of the bible:

pbzip2:             ~1.0s
bzip2:              ~1.5s
My F#:               1.4s
Ertugrul's Haskell: 88s

Note that the timing for bzip2 is a rough approximation because its maximum
block size is only 900k whereas our code is sorting the whole 5.5Mb.
Suffice to say, my F# code is certainly getting performance comparable to
that of bzip2 and is around 60x faster than Ertugrul's Haskell.

FWIW, I'm happy to spend time on interesting projects like this because I
can turn them into OCaml and F#.NET Journal articles. :-)

Here's my parallelized F# code:

  open System.Threading
  
  let inline sort cmp (a: _ array) =
    let inline swap i j =
      let t = a.[i]
      a.[i] <- a.[j]
      a.[j] <- t
    let rec qsort l u =
      if l < u then
        swap l ((l + u) / 2)
        let mutable m = l
        for i=l+1 to u do
          if cmp a.[i] a.[l] < 0 then
            m <- m + 1
            swap m i
        swap l m
        if u-l > 1000 then
          let m = m
          let f = Tasks.Future.Create(fun () -> qsort l (m-1))
          qsort (m+1) u
          f.Value
        else
          qsort l (m-1)
          qsort (m+1) u
    qsort 0 (a.Length-1)
  
  let inline cmp (str: _ array) i j =
    let rec cmp i j =
      if i=str.Length then 1 else
        if j=str.Length then -1 else
          let c = compare str.[i] str.[j] in
          if c<>0 then c else
            cmp (i+1) (j+1)
    cmp i j
  
  let bwt (str: byte array) =
    let n = str.Length
    let a = Array.init n (fun i -> i)
    sort (fun i j -> cmp str i j) a
    Array.init n (fun i -> str.[(a.[i] + n - 1) % n])

Note that I have run this on the example from Wikipedia and it did get the
correct answer. A production quality version would probably be more frugal
about the choice of pivot.

Also, the use of "inline" and functional abstraction with a
higher-order "sort" function without sacrificing any performance is of
particular interest. This is one of the features that I really like about
F# and it is easily overlooked.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 5:13:40 AM

fft1976 wrote:
> The goal of prototyping, for me, is getting at some conceptual
> clarity, which polymorphic variants, due to their wicked power, just
> don't give me.

Ok. For me, prototyping means writing in a dynamic style without the benefit
of a coherent design. OCaml is the only statically typed language that
allows me to do that thanks to its very powerful inference. In contrast,
Haskell has very weak inference.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 5:20:16 AM

Paul Rubin wrote:
> cri@tiac.net (Richard Harter) writes:
>> While we all sympathize with the limits on your time, it remains
>> that you made a major claim about the efficiency of Haskell that
>> remains unsubstantiated.
> 
> The Alioth shootout results are reasonable substantiation for general
> claims about Haskell performance.

The Alioth shootout is bad science and says nothing useful about Haskell at
all.

> Jon's specific challenge is pretty 
> worthless unless he can put up Ocaml or F# code that has the
> performance that he's demanding from Ertagul's Haskell code.

I've posted F# code that far exceeds the performance I demanded of
Ertugrul's Haskell.

Perhaps now would be a good time for you to stop whining.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 5:25:54 AM

Paul Rubin wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> First up, here are my timings for encoding a 5.5Mb copy of the bible:
>> pbzip2:             ~1.0s
>> bzip2:              ~1.5s
>> My F#:               1.4s
> 
> Nice job!  However, how much of your time did you spend writing that
> code, just to prove something that you already knew?

Took ~30mins to write but it completely shattered my prediction that F#
would be considerably slower than C.

Without my "inline" trick the time taken goes from 1.4s up to 39s.

>> FWIW, I'm happy to spend time on interesting projects like this because I
>> can turn them into OCaml and F#.NET Journal articles. :-)
> 
> Since Ertugrul isn't in the journal article business, perhaps his
> suggestion of having you offer to pay him to write code would be a
> workable alternative motivation.

Even if Ertugrul can produce the goods (which I honestly don't believe he or
anyone else can), I'd have no use for it.

> Here is another interesting Haskell vs. C benchmark:
> 
>   http://augustss.blogspot.com/2009/02/is-haskell-fast-lets-do-simple.html
> 
> ;-)

FWIW, I recently benchmarked OCaml vs HLVM on an FFT implementation and HLVM
is comparably performant: ~25% compared to optimized OCaml but ~25% faster
than OCaml on elegant code.

Here's my program for my HLVM compiler:

(* Radix-2 FFT *)

let rec zadd(((r1, i1), (r2, i2)) : (float * float) * (float * float)) :
float * float =
  r1 +. r2, i1 +. i2;;

let rec zmul(((r1, i1), (r2, i2)) : (float * float) * (float * float)) :
float * float =
  r1 *. r2 -. i1 *. i2, r1 *. i2 +. i1 *. r2;;

let rec aux1((i, n, a, a1, a2) : int * int * (float * float) array * (float
* float) array * (float * float) array) : unit =
  if i < n/2 then
    begin
      a1.(i) <- a.(2*i);
      a2.(i) <- a.(2*i+1);
      aux1(i+1, n, a, a1, a2)
    end;;

let rec aux2((k, n, a, a1, a2) : int * int * (float * float) array * (float
* float) array * (float * float) array) : unit =
  if k < n/2 then
    begin
      let t = 4. *. pi *. float_of_int k /. float_of_int n in
      a.(k) <- zadd(a1.(k), zmul(a2.(k), (cos t, -.sin t)));
      aux2(k+1, n, a, a1, a2)
    end;;

let rec aux3((k, n, a, a1, a2) : int * int * (float * float) array * (float
* float) array * (float * float) array) : unit =
  if k < n then
    begin
      let t = 4. *. pi *. float_of_int k /. float_of_int n in
      a.(k) <- zadd(a1.(k-n/2), zmul(a2.(k-n/2), (cos t, -.sin t)));
      aux3(k+1, n, a, a1, a2)
    end;;

let rec fft(a: (float * float) array) : (float * float) array =
  if length a = 1 then create(1, a.(0)) else
    begin
      let n = length a in
      let a1 = create(n/2, (0., 0.)) in
      let a2 = create(n/2, (0., 0.)) in
      aux1(0, n, a, a1, a2);
      let a1 = fft a1 in
      let a2 = fft a2 in
      aux2(0, n, a, a1, a2);
      aux3(n/2, n, a, a1, a2);
      a
    end;;

let rec ignore(a: (float * float) array) : unit = ();;

ignore(fft(create(1048576, (0.0, 0.0))));;

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 8:07:35 AM

On Jul 12, 3:20=A0am, JH wrote:
> ACL wrote:
> > On Jul 10, 10:19=A0pm, JH wrote:
> >> ACL wrote:
> >> >> >> So either Haskell is not "decent" or 200x slower is "not
> >> >> >> considerably slower".
>
> >> > You see here, the wiley troll makes a claim of comparison as if it i=
s
> >> > fact.
>
> >> Err, it is fact and I cited the source.
>
> > No you didn't. I just scrolled up. I see no study cited.
>
> Here's that citation again:
>
> http://www.mail-archive.com/haskell-cafe%40haskell.org/msg25645.html
>

One usenet post doth not a study make.

What type of 'scientist' are you exactly?
(that was rhetorical)
> >> > 'Haskell is 200x slower' than ...? he doesn't specify what it is
> >> > 200x slower than.
>
> >> I explicitly wrote "200x slower than C++".
>
> > Who cares about C++?
>
> > It seems that any language you defame has to go up against 3 or 4
> > different languages of your choosing depending on the test. I thought
> > you were the F#/OCaml schill?
>
> > Besides the haskell was *according to you* only 100x slower than C
> > code, (not C++ code). you claimed 200x
>
> The post I cited claimed 200.
>
indeed.

> >> > specifically well known for its speed.
>
> >> Did you want to compare Haskell with badly written inefficient C?
>
> > if it is badly written and inefficient haskell... then yes.
>
> We are trying to determine whether or not Haskell code can be efficient.
>

Ok, we have 2 datapoints, now to be scientists and actually able to
responsibly claim this as 'likelyhood' we need many more than 2
datapoints.

> >> > The source of which being nearly 1 megabyte of information compresse=
d.
>
> >> No, the source code to bzip2 is 170kB in under 9kLOC. The "blocksort.c=
"
> >> file that contains the equivalent of this code (and a lot more) and is
> >> only 729 LOC.
>
> > That's weird i just downloaded the source and zipped it came in at
> > ~800kb.
>
> The BZip2 distro includes the manual in several different formats, e.g. a
> 1Mb PostScript file.
>
> > Even if what you say is right, you are still comparing 100x more LOC.
> > Only 730 loc? Seriously?
>
> Sure. I won't contest that the C is far more verbose but this discussion =
was
> solely about performance.
>
> >> > We should note that it is only 100x slower than the high quality
> >> > implementation, while the claim was that haskell would be 200x
> >> > slower...
>
> >> No, the partially-implemented Haskell is already 100x slower that the
> >> complete C implementation so a full Haskell implementation based upon =
it
> >> must be over 100x slower.
>
> > That doesn't make sense. Adding code is not equal to adding extra run
> > time. Sometimes adding code makes things faster, you know.
>
> How could adding code that implements the subsequent phases of the
> compression algorithm possibly decrease the total running time?
>

He could implement a more memory efficient sorting algorithm and maybe
play with the datastructures he is using to represent things a bit.
His implementation is clearly a naive one (not that he is naive, only
you). Maybe there is an algorithmic improvement that becomes obvious
when using Haskell that is not obvious with the C code. Who knows?

> >> >> The poor performance of your Haskell code is a direct consequence o=
f
> >> >> Haskell's unpredictability. Obviously you failed to predict how bad
> >> >> your code was or you would not have posted an example that contradi=
cts
> >> >> your own assertions.
>
> >> > He omits the fact that the poor performance is a result of not
> >> > comparing apples to apples in any sort of reasonable manner.
>
> >> You misunderstood the comparison.
>
> > It seems it is a bad comparison....
>
> Indeed, it turns out that Ertugrul's Haskell implementation is actually
> broken.
>
So we can throw out the datapoint then?
You are now claiming that Haskell is slower than C and basing the
claim on 1 usenet post.

Awesome.

> >> > He also omits the fact that the author admited that it wasn't the
> >> > highest quality implementation of zip compression.
>
> >> Ertugrul claimed he could write performant Haskell and then didn't.
>
> > I think he claimed it could be written, not that he was writing it.
>
> Indeed, this is the second time he has made a claim about Haskell only to
> prove himself wrong.
>

'prove himself wrong' vs. 'not make his point'.

Nothing has been proven here.
0
Reply anonymous.c.lisper (176) 7/14/2009 12:02:45 PM

On Jul 14, 1:25=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Paul Rubin wrote:
> > c...@tiac.net (Richard Harter) writes:
> >> While we all sympathize with the limits on your time, it remains
> >> that you made a major claim about the efficiency of Haskell that
> >> remains unsubstantiated.
>
> > The Alioth shootout results are reasonable substantiation for general
> > claims about Haskell performance.
>
> The Alioth shootout is bad science and says nothing useful about Haskell =
at
> all.
>

Your posts are just as much bad science.


> > Jon's specific challenge is pretty
> > worthless unless he can put up Ocaml or F# code that has the
> > performance that he's demanding from Ertagul's Haskell code.
>
> I've posted F# code that far exceeds the performance I demanded of
> Ertugrul's Haskell.
>
> Perhaps now would be a good time for you to stop whining.
>

Are you secretly rush limbaugh?

'Shut up! Shut up! Shut up!
'Stop Whining!'

> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy.com=
/?u

0
Reply anonymous.c.lisper (176) 7/14/2009 12:05:38 PM

On 2009-07-13 17:48:03 -0400, Larry D'Anna <larry@elder-gods.org> said:

> Do you really imagine monads serve no useful purpose whatsoever, and that Simon
> Peyton-Jones is just too stupid too see how worthless they are?  Or 
> maybe, is it
> possible that there's something you've missed, that there are certain things
> that monads enable that aren't possible without them.

Monads can indeed accomplish a goal which cannot be achieved with 
traditional side effects, but that goal (maintaining *pure* functional 
semantics) is not a goal that I and many other programmers consider 
worthwhile given the cognitive overhead.

-- 
Raffael Cavallaro

0
Reply raffaelcavallaro5985 (306) 7/14/2009 2:34:03 PM

Nobody <nobody@nowhere.com> writes:

> On Mon, 13 Jul 2009 00:48:49 -0400, Raffael Cavallaro wrote:
>
>> It is perfectly legitimate (in fact, it is the human cognitive norm)
>> to conceptualize the world as inherently stateful and constantly
>> mutating.
>
> You have a choice in how you conceptualise the world. I don't think the
> Church-Turing thesis is news to anyone here.

What relevance do you take the Church-Turing thesis to have to Raffael's
remark?

-- 
Aatu Koskensilta (aatu.koskensilta@uta.fi)

"Wovon mann nicht sprechen kann, dar�ber muss man schweigen"
 - Ludwig Wittgenstein, Tractatus Logico-Philosophicus
0
Reply aatu.koskensilta1 (232) 7/14/2009 3:19:58 PM

In article <87k52bz3z5.fsf@alatheia.truth.invalid>,
Aatu Koskensilta  <aatu.koskensilta@uta.fi> wrote:
> Nobody <nobody@nowhere.com> writes:
> > On Mon, 13 Jul 2009 00:48:49 -0400, Raffael Cavallaro wrote:
> >> It is perfectly legitimate (in fact, it is the human cognitive norm)
> >> to conceptualize the world as inherently stateful and constantly
> >> mutating.
> >
> > You have a choice in how you conceptualise the world. I don't think the
> > Church-Turing thesis is news to anyone here.
> 
> What relevance do you take the Church-Turing thesis to have to Raffael's
> remark?

I am guessing the focus here is on Turing's result that
lambda-definability and Turing-computability coincide. These are the
archetypical "imperative" and "functional" ways of formalizing
computability, so their equivalence is a handy way of pointing out
that either approach can be used.

Of course this perceived distinction between them is mostly cultural.
Both lambda calculus and Turing machines are formalized as state
transition systems, and in both cases it's just a matter of
perspective whether to think of the state transitions as functions
with an input state and an output state, or as inherently effectful
operations that "change" the state of the system. 

I'm not sure if there even is any real difference between these
perspectives, at least any that could be articulated. That's why the
bickering in this thread about the true nature of side effects seems
particularly silly.


Lauri
0
Reply la (473) 7/14/2009 4:50:07 PM

Lauri Alanko <la@iki.fi> writes:

> In article <87k52bz3z5.fsf@alatheia.truth.invalid>,
> Aatu Koskensilta  <aatu.koskensilta@uta.fi> wrote:
> 
>> What relevance do you take the Church-Turing thesis to have to
>> Raffael's remark?
>
> I am guessing the focus here is on Turing's result that
> lambda-definability and Turing-computability coincide.

Possibly, but that's not the Church-Turing thesis.

> These are the archetypical "imperative" and "functional" ways of
> formalizing computability, so their equivalence is a handy way of
> pointing out that either approach can be used.

That may well be. The Church-Turing thesis, on the other hand, is a
purely extensional thesis concerning mathematical functions, for which
the issue of side-effects does not arise, or indeed make any sense at
all.

-- 
Aatu Koskensilta (aatu.koskensilta@uta.fi)

"Wovon mann nicht sprechen kann, dar�ber muss man schweigen"
 - Ludwig Wittgenstein, Tractatus Logico-Philosophicus
0
Reply aatu.koskensilta1 (232) 7/14/2009 7:13:19 PM

ACL wrote:
>> Indeed, this is the second time he has made a claim about Haskell only to
>> prove himself wrong.
> 
> 'prove himself wrong' vs. 'not make his point'.
> 
> Nothing has been proven here.

Yes, of course. We are trying to disprove something.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/14/2009 7:22:30 PM

In article <877hybyt68.fsf@alatheia.truth.invalid>,
Aatu Koskensilta  <aatu.koskensilta@uta.fi> wrote:
> Lauri Alanko <la@iki.fi> writes:
> > I am guessing the focus here is on Turing's result that
> > lambda-definability and Turing-computability coincide.
> 
> Possibly, but that's not the Church-Turing thesis.

True, but that's the reason it's _called_ "the Church-Turing thesis",
and not only "Church's thesis" and "Turing's thesis". So the fact that
there is such a meaningful concept as "the Church-Turing thesis" is
quite relevant here, even though the truth value of the thesis is not.

> That may well be. The Church-Turing thesis, on the other hand, is a
> purely extensional thesis concerning mathematical functions,

Only the extension of the thesis is extensional. :)


Lauri
0
Reply la (473) 7/14/2009 8:23:17 PM

On Tue, 14 Jul 2009 16:50:07 +0000, Lauri Alanko wrote:

>> >> It is perfectly legitimate (in fact, it is the human cognitive norm)
>> >> to conceptualize the world as inherently stateful and constantly
>> >> mutating.
>> >
>> > You have a choice in how you conceptualise the world. I don't think the
>> > Church-Turing thesis is news to anyone here.
>> 
>> What relevance do you take the Church-Turing thesis to have to Raffael's
>> remark?
> 
> I am guessing the focus here is on Turing's result that
> lambda-definability and Turing-computability coincide. These are the
> archetypical "imperative" and "functional" ways of formalizing
> computability, so their equivalence is a handy way of pointing out
> that either approach can be used.

FWIW: yes, that was my point.

0
Reply nobody (4804) 7/14/2009 9:23:25 PM

Jon Harrop <jon@ffconsultancy.com> writes:
> Of course there is a sane reason! The *only* way you can justify the
> following claim is by crippling your hash table implementation:
>
>   "Compared to a hash table, a well-implemented purely functional tree data
> structure will perform competitively. You should not approach trees with
> the assumption that your code will pay a performance penalty." - Real World
> Haskell

That's not the only way.  If one is interested in worst-case
performance then hash tables that use a O(n) mechanism to deal with
collison (as does the version in the O'Caml standard library) can be
orders of mangnitude worse than even a purely functional
(well-implemented aka balanced) tree as your own O'Caml test programs
show.  The only way to avoid the disastrous hash table performance to
to keep n small, but for some reason you don't mention that despite
the fact that we went over this twice within the last few months in
comp.lang.functional.
0
Reply stephen104 (378) 7/15/2009 3:41:07 AM

Stephen J. Bevan wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> Of course there is a sane reason! The *only* way you can justify the
>> following claim is by crippling your hash table implementation:
>>
>>   "Compared to a hash table, a well-implemented purely functional tree
>>   data
>> structure will perform competitively. You should not approach trees with
>> the assumption that your code will pay a performance penalty." - Real
>> World Haskell
> 
> That's not the only way.  If one is interested in worst-case
> performance

If one is *only* interested in worse case performance.

> then hash tables that use a O(n) mechanism to deal with 
> collison

If the hash table does and if the tree does not.

> (as does the version in the O'Caml standard library)

Yes.

> can be  
> orders of mangnitude worse than even a purely functional
> (well-implemented aka balanced) tree

If he meant balanced when he said "well implemented".

> as your own O'Caml test programs show.

That is incorrect.

> The only way to avoid the disastrous hash table performance to 
> to keep n small,

That is also incorrect.

> but for some reason you don't mention that despite 
> the fact that we went over this twice within the last few months in
> comp.lang.functional.

You took data about batch resizing in OCaml's implementation and incorrectly
extrapolated to all hash tables and even to completely different forms of
worst case. Then you also believed that all purely functional trees were
balanced. I referenced counter examples in every case. Nothing remains to
be debated.

If whoever wrote that part of Real World Haskell meant to refer only to the
worst case, only to O(n) hash tables and only to O(log n) trees then they
should have written that, very different, statement. As it is, what they
wrote is grossly misleading at best.

You get what you pay for.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/15/2009 10:48:28 AM

Ertugrul Söylemez wrote:
> Jon Harrop <jon@ffconsultancy.com> wrote:
> 
>> > What's wrong with purely functional languages?
>>
>> . Unpredictable performance.
> 
> Wrong.

Ertugrul just disproved this for a third time on comp.lang.haskell, BTW.

He posted this prime sieve and claimed that moving to boxed arrays did not
make the program scale worse:

  module Main where

  import Control.Monad
  import Control.Monad.ST
  import Data.Array.ST
  import Data.Array.Unboxed
  import System.Environment


  soe :: Int -> ST s (STUArray s Int Bool)
  soe n = do
    sieve <- newArray (2,n) True
    let !m = div n 2
    forM_ [2..m] $ \i -> do
      b <- readArray sieve i
      when b $ forM_ [i+i, i+i+i .. n] $ \j -> writeArray sieve j False
    return sieve


  soeList :: (Enum a, Num a) => Int -> [a]
  soeList n = map fst . filter snd . zip [2..] . elems . runSTUArray $ soe n


  main :: IO ()
  main = getArgs >>= mapM_ (print . length . soeList . read)

Compiled with ghc --make -O2, ratios of running times on my machine are:

0.5M:  2.52
1.0M:  4
2.0M:  7.3
3.0M:  9.4
4.0M: 13.4

The boxed version is clearly relatively slower on larger inputs. The reason
is that writing a single element into an array is O(n) due to a
long-standing perf bug in GHC's run-time.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/15/2009 11:11:54 AM

Scott Burson wrote:
> And you think Ertugrul doesn't have better things to do than
> argue on Usenet?

Having lost two benchmark challenges here, Ertugrul confined the discussion
to comp.lang.haskell only and posted another challenge the next day:

http://groups.google.com/group/comp.lang.haskell/msg/c86dd206a7b1e112?hl=en

He lost that one too.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/15/2009 11:23:38 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> Stephen J. Bevan wrote:
>> Jon Harrop <jon@ffconsultancy.com> writes:
> If one is *only* interested in worse case performance.

I am.


>> as your own O'Caml test programs show.
>
> That is incorrect.

You snipped away the full context which is :-

  If one is interested in worst-case performance then hash tables that
  use a O(n) mechanism to deal with collison (as does the version in the
  O'Caml standard library) can be orders of mangnitude worse than even a
  purely functional (well-implemented aka balanced) tree as your own
  O'Caml test programs show.

In <87hc0jj3qm.fsf@dnsalias.com> the graphs of your O'Caml programs
(which use an hash table with O(n) worst case) are shown and the worst
case preformance is obvious.  If you believe there is something
incorrect in what I wrote then that's incorrect perhaps you'd do me
the courtesy of giving a reason.


>> The only way to avoid the disastrous hash table performance to 
>> to keep n small,
>
> That is also incorrect.

In <fcSdnVtZsMW5QXHUnZ2dnUVZ8q6dnZ2d@posted.plusnet> you wrote :-

  > > 2. The maximum time for any of the map runs is < 16,000.  The maximum
  > >    run time for the hash table is > 1,000,000.
  > 
  > For large hash tables or maps, yes. That justifies your original assertion
  > that insertion time for large hash tables is often bad.

So for me to be incorrect I assume that you have some way other
solution than keeping n small for O(n) hash tables to avoid the
performance issue?  Obviousy if one replaces the list in the hash
table by a balanced tree then one gets O(log n) worst case but now the
worst case is no better than the balanced tree.


> You took data about batch resizing in OCaml's implementation and
> incorrectly extrapolated to all hash tables and even to completely
> different forms of worst case.

In <26GdnZdJQL2hunbUnZ2dnUVZ8vKdnZ2d@posted.plusnet> you wrote :-

  > > Can I assume at this point you contend that a hash table will give the
  > > best performance for this problem -- with or without having to deal
  > > with the issue of re-sizing.  Did you code it and measure the
  > > performance or is this based on results using a hash table in other
  > > problem domains, particularly ones where best/average case performance
  > > is measured and not worst case performance?

  > The relevant performance measurements are already graphed in both OCaml for
  > Scientists (page 80) and F# for Scientists (page 88).

Thus you provided the O'Caml code from which you extrapolated a claim
for all hash tables.  I simply used your data but looked at the worst
case performance.  I agree that the performance of the O'Caml hash
table isn't necessarily the same as all hash tables but since the
you used it to make claims about best-case performance why am I not
allowed to make a claim about worst case performance?


> Then you also believed that all purely functional trees were
> balanced.

Care to quote me writing that?  What I believed and still believe is
that "well-implemented trees" implies balanced as I stated in
<86hbym2i3i.fsf@dino.dnsalias.com>.


> I referenced counter examples in every case.

Citing a non-balanced tree isn't a counter example when non-balanced
trees were never an issue.


> If whoever wrote that part of Real World Haskell meant to refer only
> to the worst case, only to O(n) hash tables and only to O(log n)
> trees then they should have written that, very different,
> statement. As it is, what they wrote is grossly misleading at best.

Unlike your even handed statements about hash tables and trees?
0
Reply stephen104 (378) 7/15/2009 2:06:08 PM

Lauri Alanko <la@iki.fi> writes:

> In article <877hybyt68.fsf@alatheia.truth.invalid>,
> Aatu Koskensilta  <aatu.koskensilta@uta.fi> wrote:
>
>> Possibly, but that's not the Church-Turing thesis.
>
> True, but that's the reason it's _called_ "the Church-Turing thesis",
> and not only "Church's thesis" and "Turing's thesis". So the fact that
> there is such a meaningful concept as "the Church-Turing thesis" is
> quite relevant here, even though the truth value of the thesis is not.

The thesis -- or, rather, two theses that turned out to be equivalent --
is called the Church-Thuring thesis because it was independently
proposed by both Church and Turing, originally as a definition rather
than thesis. (The often used shorter form "Church's thesis" is a bit odd
given the thesis in Church's formulation has not much any intrinsic
plausibility.) That you should find the naming of the thesis significant
is a bit baffling but as has now been explained your original suggestion
as to its relevance was what Nobody had in mind.

>> That may well be. The Church-Turing thesis, on the other hand, is a
>> purely extensional thesis concerning mathematical functions,
>
> Only the extension of the thesis is extensional. :)

I am unsure what to make of this jocular comment.

-- 
Aatu Koskensilta (aatu.koskensilta@uta.fi)

"Wovon mann nicht sprechen kann, dar�ber muss man schweigen"
 - Ludwig Wittgenstein, Tractatus Logico-Philosophicus
0
Reply aatu.koskensilta1 (232) 7/15/2009 2:37:32 PM

Stephen J. Bevan wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> Stephen J. Bevan wrote:
>>> Jon Harrop <jon@ffconsultancy.com> writes:
>> If one is *only* interested in worse case performance.
> 
> I am.

Then you are off topic.

>>> as your own O'Caml test programs show.
>>
>> That is incorrect.
> 
> You snipped away the full context which is :-
> 
>   If one is interested in worst-case performance then hash tables that
>   use a O(n) mechanism to deal with collison (as does the version in the
>   O'Caml standard library) can be orders of mangnitude worse than even a
>   purely functional (well-implemented aka balanced) tree as your own
>   O'Caml test programs show.
> 
> In <87hc0jj3qm.fsf@dnsalias.com> the graphs of your O'Caml programs
> (which use an hash table with O(n) worst case) are shown and the worst
> case preformance is obvious.  If you believe there is something
> incorrect in what I wrote then that's incorrect perhaps you'd do me
> the courtesy of giving a reason.

You are describing one worst case scenario (collisions) and citing
irrelevant data about another (resizing).

>>> The only way to avoid the disastrous hash table performance to
>>> to keep n small,
>>
>> That is also incorrect.
> 
> In <fcSdnVtZsMW5QXHUnZ2dnUVZ8q6dnZ2d@posted.plusnet> you wrote :-
> 
>   > > 2. The maximum time for any of the map runs is < 16,000.  The
>   > > maximum
>   > >    run time for the hash table is > 1,000,000.
>   > 
>   > For large hash tables or maps, yes. That justifies your original
>   > assertion that insertion time for large hash tables is often bad.
> 
> So for me to be incorrect I assume that you have some way other
> solution than keeping n small for O(n) hash tables to avoid the
> performance issue?  Obviousy if one replaces the list in the hash
> table by a balanced tree then one gets O(log n) worst case but now the
> worst case is no better than the balanced tree.

Yes.

>> You took data about batch resizing in OCaml's implementation and
>> incorrectly extrapolated to all hash tables and even to completely
>> different forms of worst case.
> 
> In <26GdnZdJQL2hunbUnZ2dnUVZ8vKdnZ2d@posted.plusnet> you wrote :-
> 
>   > > Can I assume at this point you contend that a hash table will give
>   > > the best performance for this problem -- with or without having to
>   > > deal
>   > > with the issue of re-sizing.  Did you code it and measure the
>   > > performance or is this based on results using a hash table in other
>   > > problem domains, particularly ones where best/average case
>   > > performance is measured and not worst case performance?
> 
>   > The relevant performance measurements are already graphed in both
>   > OCaml for Scientists (page 80) and F# for Scientists (page 88).
> 
> Thus you provided the O'Caml code from which you extrapolated a claim
> for all hash tables.

What claim have I made about all hash tables?

> I simply used your data but looked at the worst 
> case performance,

Which worst case performance?

> I agree that the performance of the O'Caml hash 
> table isn't necessarily the same as all hash tables but since the
> you used it to make claims about best-case performance why am I not
> allowed to make a claim about worst case performance?

Logic.

>> Then you also believed that all purely functional trees were
>> balanced.
> 
> Care to quote me writing that?  What I believed and still believe is
> that "well-implemented trees" implies balanced as I stated in
> <86hbym2i3i.fsf@dino.dnsalias.com>.

Splay trees?

>> I referenced counter examples in every case.
> 
> ...non-balanced trees were never an issue.

Not true.

>> If whoever wrote that part of Real World Haskell meant to refer only
>> to the worst case, only to O(n) hash tables and only to O(log n)
>> trees then they should have written that, very different,
>> statement. As it is, what they wrote is grossly misleading at best.
> 
> Unlike your even handed statements about hash tables and trees?

Stop wasting my time.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/15/2009 10:02:06 PM

Jon Harrop <jon@ffconsultancy.com> writes:
> Stephen J. Bevan wrote:
>> Jon Harrop <jon@ffconsultancy.com> writes:
>>> Stephen J. Bevan wrote:
>>>> Jon Harrop <jon@ffconsultancy.com> writes:
>>> If one is *only* interested in worse case performance.
>> 
>> I am.
>
> Then you are off topic.

The topic is your claim that :-

> Of course there is a sane reason! The *only* way you can justify the
> following claim is by crippling your hash table implementation:
>
>  "Compared to a hash table, a well-implemented purely functional tree data
> structure will perform competitively. You should not approach trees with
> the assumption that your code will pay a performance penalty." - Real World
> Haskell

One does not have to cripple the hash table to justify the claim, your
own O'Caml test program is justification enough.


>> In <87hc0jj3qm.fsf@dnsalias.com> the graphs of your O'Caml programs
>> (which use an hash table with O(n) worst case) are shown and the worst
>> case preformance is obvious.  If you believe there is something
>> incorrect in what I wrote then that's incorrect perhaps you'd do me
>> the courtesy of giving a reason.
>
> You are describing one worst case scenario (collisions) and citing
> irrelevant data about another (resizing).

I was quite clear in my response that I'm interested in worst case
performance so of course I'm going to pick scenarios that show worst
case performance.  If you don't want to consider worst case
performance then you should take your own advice about writing
misleading claims.  As to irrelevant data, it is from your test
program.  If the results are irrelevant then why did you point to
them?  If you want to argue that some parts of the results are
meaningful and some aren't then re-write your test so that it doesn't
display any negative results.


>> So for me to be incorrect I assume that you have some way other
>> solution than keeping n small for O(n) hash tables to avoid the
>> performance issue?  Obviousy if one replaces the list in the hash
>> table by a balanced tree then one gets O(log n) worst case but now the
>> worst case is no better than the balanced tree.
>
> Yes.

Is that yes you have another way or yes you use balanced trees.  If
the former that was a stunningly unenlightending answer and if the
latter then why didn't you use that when writing your O'Caml test
programs that you claimed as evidence of good performance of hash
tables?


>>> You took data about batch resizing in OCaml's implementation and
>>> incorrectly extrapolated to all hash tables and even to completely
>>> different forms of worst case.
>> 
>> In <26GdnZdJQL2hunbUnZ2dnUVZ8vKdnZ2d@posted.plusnet> you wrote :-
>> 
>>   > > Can I assume at this point you contend that a hash table will give
>>   > > the best performance for this problem -- with or without having to
>>   > > deal
>>   > > with the issue of re-sizing.  Did you code it and measure the
>>   > > performance or is this based on results using a hash table in other
>>   > > problem domains, particularly ones where best/average case
>>   > > performance is measured and not worst case performance?
>> 
>>   > The relevant performance measurements are already graphed in both
>>   > OCaml for Scientists (page 80) and F# for Scientists (page 88).
>> 
>> Thus you provided the O'Caml code from which you extrapolated a claim
>> for all hash tables.
>
> What claim have I made about all hash tables?

Back in April in <vOGdnXkDCqCvC3_UnZ2dnUVZ8tmdnZ2d@posted.plusnet> you
wrote :-

> Hash tables are one of the most important data structures and are the only
> performant way to implement a dictionary in most cases.

That led to the above quote where rather than argue about "most" I
challenged you about one specific problem and you were free to choose
the hash table implementation.  Instead you quoted the results of your
tests as evidence.  I can hardly be faulted for pointing out the worst
case peformance of the hash table that you claimed showed that hash
tables would give the best performance for the specified problem.
You then modified your approach to a trie of hash tables but with a
trie depth of > 20 and eventually in
<qsWdnVZ6GOy_03DUnZ2dnUVZ8vOdnZ2d@posted.plusnet> you wrote :-

> For IPv6, I agree that a balanced tree looks best (better than any
> kind of trie or hash table).

which speaks for itself. 


>> I simply used your data but looked at the worst 
>> case performance,
>
> Which worst case performance?

The performance of insert/lookup/delete as n varies.


>> I agree that the performance of the O'Caml hash 
>> table isn't necessarily the same as all hash tables but since the
>> you used it to make claims about best-case performance why am I not
>> allowed to make a claim about worst case performance?
>
> Logic.

"Logic" iasn't argument.  Either we can both extrapolate results for
_all_ hash tables from your test or neither of us can.


>>> Then you also believed that all purely functional trees were
>>> balanced.
>> 
>> Care to quote me writing that?  What I believed and still believe is
>> that "well-implemented trees" implies balanced as I stated in
>> <86hbym2i3i.fsf@dino.dnsalias.com>.
>
> Splay trees?

What do splay trees have to do with the above?  They aren't balanced.


>>> I referenced counter examples in every case.
>> 
>> ...non-balanced trees were never an issue.
>
> Not true.

I should have wrote "not an issue for me".  Clearly you think they are
an issue because you apparently attached no meaning to "well
implemented" and so assumed any tree was valid.  That was all covered
in <yq6dnXhoV63e9azXnZ2dnUVZ8iidnZ2d@brightview.co.uk> and my respose
<86hbym2i3i.fsf@dino.dnsalias.com>.  My news server does not register
any followup from you so quite why you are bringing it up again isn't
clear to me.


>>> If whoever wrote that part of Real World Haskell meant to refer only
>>> to the worst case, only to O(n) hash tables and only to O(log n)
>>> trees then they should have written that, very different,
>>> statement. As it is, what they wrote is grossly misleading at best.
>> 
>> Unlike your even handed statements about hash tables and trees?
>
> Stop wasting my time.

If you aren't willing to defend what you write then the simple answer
is to not write anything.
0
Reply stephen104 (378) 7/16/2009 2:21:45 AM

Stephen J. Bevan wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> Stephen J. Bevan wrote:
>>> Jon Harrop <jon@ffconsultancy.com> writes:
>>>> Stephen J. Bevan wrote:
>>>>> Jon Harrop <jon@ffconsultancy.com> writes:
>>>> If one is *only* interested in worse case performance.
>>> 
>>> I am.
>>
>> Then you are off topic.
> 
> The topic is your claim that :-
> 
>> Of course there is a sane reason! The *only* way you can justify the
>> following claim is by crippling your hash table implementation:
>>
>>  "Compared to a hash table, a well-implemented purely functional tree
>>  data
>> structure will perform competitively. You should not approach trees with
>> the assumption that your code will pay a performance penalty." - Real
>> World Haskell
> 
> One does not have to cripple the hash table to justify the claim,

Consider the task of filling your dictionary (hash table or purely
functional tree) with ten million machine-precision integers. The only way
you can possibly make a purely functional tree "perform competitively" is
by crippling the hash table.

That is a counter example to the statement made in Real World Haskell, i.e.
their statement was factually incorrect.

> your own O'Caml test program is justification enough.

My OCaml test program does not undermine the above counter example.

>>> In <87hc0jj3qm.fsf@dnsalias.com> the graphs of your O'Caml programs
>>> (which use an hash table with O(n) worst case) are shown and the worst
>>> case preformance is obvious.  If you believe there is something
>>> incorrect in what I wrote then that's incorrect perhaps you'd do me
>>> the courtesy of giving a reason.
>>
>> You are describing one worst case scenario (collisions) and citing
>> irrelevant data about another (resizing).
> 
> I was quite clear in my response that I'm interested in worst case
> performance so of course I'm going to pick scenarios that show worst
> case performance.

That's fine but you must clarify which worst case you are referring to.

> If you don't want to consider worst case 
> performance then you should take your own advice about writing
> misleading claims.

I am more than happy to change the subject completely and talk about worst
case performance instead of the statement from Real World Haskell which did
not mention worse case performance.

> As to irrelevant data, it is from your test 
> program.  If the results are irrelevant then why did you point to
> them?

I did not point to them, you did.

> If you want to argue that some parts of the results are 
> meaningful and some aren't then re-write your test so that it doesn't
> display any negative results.

Negative results?

>>> So for me to be incorrect I assume that you have some way other
>>> solution than keeping n small for O(n) hash tables to avoid the
>>> performance issue?  Obviousy if one replaces the list in the hash
>>> table by a balanced tree then one gets O(log n) worst case but now the
>>> worst case is no better than the balanced tree.
>>
>> Yes.
> 
> Is that yes you have another way or yes you use balanced trees.

Yes, you can implement the buckets of the hash table as mutable balanced
trees to get O(log n) worst case performance.

> If 
> the former that was a stunningly unenlightending answer and if the
> latter then why didn't you use that when writing your O'Caml test
> programs that you claimed as evidence of good performance of hash
> tables?

Firstly, I never claimed that. Secondly, my OCaml test was completely
unrelated to this worst case.

>>>> You took data about batch resizing in OCaml's implementation and
>>>> incorrectly extrapolated to all hash tables and even to completely
>>>> different forms of worst case.
>>> 
>>> In <26GdnZdJQL2hunbUnZ2dnUVZ8vKdnZ2d@posted.plusnet> you wrote :-
>>> 
>>>   > > Can I assume at this point you contend that a hash table will give
>>>   > > the best performance for this problem -- with or without having to
>>>   > > deal
>>>   > > with the issue of re-sizing.  Did you code it and measure the
>>>   > > performance or is this based on results using a hash table in
>>>   > > other problem domains, particularly ones where best/average case
>>>   > > performance is measured and not worst case performance?
>>> 
>>>   > The relevant performance measurements are already graphed in both
>>>   > OCaml for Scientists (page 80) and F# for Scientists (page 88).
>>> 
>>> Thus you provided the O'Caml code from which you extrapolated a claim
>>> for all hash tables.
>>
>> What claim have I made about all hash tables?
> 
> Back in April in <vOGdnXkDCqCvC3_UnZ2dnUVZ8tmdnZ2d@posted.plusnet> you
> wrote :-
> 
>> Hash tables are one of the most important data structures and are the
>> only performant way to implement a dictionary in most cases.

That is not a claim about all hash tables.

> That led to the above quote where rather than argue about "most" I
> challenged you about one specific problem and you were free to choose
> the hash table implementation.  Instead you quoted the results of your
> tests as evidence.  I can hardly be faulted for pointing out the worst
> case peformance of the hash table that you claimed showed that hash
> tables would give the best performance for the specified problem.

That never happened.

> You then modified your approach to a trie of hash tables but with a
> trie depth of > 20 and eventually in
> <qsWdnVZ6GOy_03DUnZ2dnUVZ8vOdnZ2d@posted.plusnet> you wrote :-
> 
>> For IPv6, I agree that a balanced tree looks best (better than any
>> kind of trie or hash table).
> 
> which speaks for itself.

Irrelevant. I was talking about impure balanced trees there and am talking
about pure "well implemented" trees here.

>>> I simply used your data but looked at the worst
>>> case performance,
>>
>> Which worst case performance?
> 
> The performance of insert/lookup/delete as n varies.

Which one?

>>> I agree that the performance of the O'Caml hash
>>> table isn't necessarily the same as all hash tables but since the
>>> you used it to make claims about best-case performance why am I not
>>> allowed to make a claim about worst case performance?
>>
>> Logic.
> 
> "Logic" iasn't argument.  Either we can both extrapolate results for
> _all_ hash tables from your test or neither of us can.

My concrete example constitutes a counter example. Yours does not.

>>>> Then you also believed that all purely functional trees were
>>>> balanced.
>>> 
>>> Care to quote me writing that?  What I believed and still believe is
>>> that "well-implemented trees" implies balanced as I stated in
>>> <86hbym2i3i.fsf@dino.dnsalias.com>.
>>
>> Splay trees?
> 
> What do splay trees have to do with the above?  They aren't balanced.

Only for some definition of "balanced" that makes your argument circular.

>>>> I referenced counter examples in every case.
>>> 
>>> ...non-balanced trees were never an issue.
>>
>> Not true.
> 
> I should have wrote "not an issue for me". Clearly you think they are 
> an issue because you apparently attached no meaning to "well
> implemented" and so assumed any tree was valid.

I did not presume that Real World Haskell meant "balanced" when it
said "well implemented".

>>>> If whoever wrote that part of Real World Haskell meant to refer only
>>>> to the worst case, only to O(n) hash tables and only to O(log n)
>>>> trees then they should have written that, very different,
>>>> statement. As it is, what they wrote is grossly misleading at best.
>>> 
>>> Unlike your even handed statements about hash tables and trees?
>>
>> Stop wasting my time.
> 
> If you aren't willing to defend what you write then the simple answer
> is to not write anything.

You are trying to get me to defend things that I have not written.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/16/2009 5:00:50 AM

On Jul 15, 4:23=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Scott Burson wrote:
> > And you think Ertugrul doesn't have better things to do than
> > argue on Usenet?
>
> Having lost two benchmark challenges here, Ertugrul confined the discussi=
on
> to comp.lang.haskell only and posted another challenge the next day:
>
> http://groups.google.com/group/comp.lang.haskell/msg/c86dd206a7b1e112...
>
> He lost that one too.

This is one of the times you remind me of a high-school student
heckling the students of a rival school because your team won the
football game.  It's thoroughly adolescent behavior.  ("You suck!  We
rule!" -- it's the same thing even though you don't use those words.)

I had no horse in this race.  I've never even used Haskell.  I was
just pointing out that you said something ridiculous (and also very
adolescent in its black-and-white quality -- infinite development
time, indeed!).

I thank Ertugrul for giving of his time to contribute to the state of
our knowledge of programming languages.

-- Scott
0
Reply FSet.SLB (346) 7/16/2009 5:08:23 AM

Scott Burson wrote:

> On Jul 15, 4:23 am, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Scott Burson wrote:
>> > And you think Ertugrul doesn't have better things to do than
>> > argue on Usenet?
>>
>> Having lost two benchmark challenges here, Ertugrul confined the
>> discussion to comp.lang.haskell only and posted another challenge the
>> next day:
>>
>> http://groups.google.com/group/comp.lang.haskell/msg/c86dd206a7b1e112...
>>
>> He lost that one too.
> 
> This is one of the times you remind me of a high-school student
> heckling the students of a rival school because your team won the
> football game.  It's thoroughly adolescent behavior.  ("You suck!  We
> rule!" -- it's the same thing even though you don't use those words.)
> 
> I had no horse in this race.  I've never even used Haskell.  I was
> just pointing out that you said something ridiculous (and also very
> adolescent in its black-and-white quality -- infinite development
> time, indeed!).
> 
> I thank Ertugrul for giving of his time to contribute to the state of
> our knowledge of programming languages.
> 
> -- Scott

For every man that told him he sucked, he built a wall to echo the sucking 
more.

Wine and honey are quite nice, but vinegar is quicker when viewed out the 
side window of the door.

To those that learn to taste, and choose, the fragrance and effects of honey 
are something that amuse.

Both men liked honey, and both sought to find more.  The men could not 
agree, on which path was better, and what the paths were for.

The men disagreed until their days came to an end.  The path by this time, 
was nothing but sand.  Blended, and molded into where it came from, nothing 
but an illusion, of what it once was.

-GPS

0
Reply georgeps (404) 7/16/2009 6:36:07 AM

On Jul 13, 10:20=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> fft1976 wrote:
> > The goal of prototyping, for me, is getting at some conceptual
> > clarity, which polymorphic variants, due to their wicked power, just
> > don't give me.
>
> Ok. For me, prototyping means writing in a dynamic style without the bene=
fit
> of a coherent design. OCaml is the only statically typed language that
> allows me to do that thanks to its very powerful inference. In contrast,
> Haskell has very weak inference.
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy.com=
/?u

By the way, someone is posting on Clojure ML under "JoHn
Harrop" (singing praises to Clojure). So I have to ask, is that poster
an impostor?

0
Reply fft1976 (100) 7/16/2009 10:24:13 AM

On Jul 16, 12:08=A0am, Scott Burson <FSet....@gmail.com> wrote:
> I thank Ertugrul for giving of his time to contribute to the state of
> our knowledge of programming languages.
>
> -- Scott

I would thank them even more if they move this Haskell/F# brawl
outside of cll.

Bobi
0
Reply slobodan.blazeski (1459) 7/16/2009 10:38:36 AM

On Jul 16, 6:24=A0am, fft1976 <fft1...@gmail.com> wrote:
> On Jul 13, 10:20=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>
> > fft1976 wrote:
> > > The goal of prototyping, for me, is getting at some conceptual
> > > clarity, which polymorphic variants, due to their wicked power, just
> > > don't give me.
>
> > Ok. For me, prototyping means writing in a dynamic style without the be=
nefit
> > of a coherent design. OCaml is the only statically typed language that
> > allows me to do that thanks to its very powerful inference. In contrast=
,
> > Haskell has very weak inference.
>
> > --
> > Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy.c=
om/?u
>
> By the way, someone is posting on Clojure ML under "JoHn
> Harrop" (singing praises to Clojure). So I have to ask, is that poster
> an impostor?

I've looked at some of JoHn Harrop's posts on the Clojure ML. He seems
to be actively coding in Clojure, and in addition, seems to have some
understanding of the Lisp Way. I think he just happens to have the
same last name as our amphibian friend.

0
Reply larryliberty (26) 7/16/2009 12:34:17 PM

On 16 Jul., 16:09, Jon Harrop <j...@ffconsultancy.com> wrote:
> fft1976 wrote:
> > By the way, someone is posting on Clojure ML under "JoHn
> > Harrop" (singing praises to Clojure). So I have to ask, is that poster
> > an impostor?
>
> Yes, I noticed that. I think he's just another functional programmer with a
> very similar name to mine.
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy.com/?u

No sock puppet of yours this time?

0
Reply joswig8642 (2198) 7/16/2009 1:04:28 PM

fft1976 wrote:
> By the way, someone is posting on Clojure ML under "JoHn
> Harrop" (singing praises to Clojure). So I have to ask, is that poster
> an impostor?

Yes, I noticed that. I think he's just another functional programmer with a
very similar name to mine.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/16/2009 2:09:49 PM

On Jul 16, 5:34=A0am, Larry Coleman <larrylibe...@yahoo.com> wrote:
> On Jul 16, 6:24=A0am, fft1976 <fft1...@gmail.com> wrote:
>
>
>
> > On Jul 13, 10:20=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>
> > > fft1976 wrote:
> > > > The goal of prototyping, for me, is getting at some conceptual
> > > > clarity, which polymorphic variants, due to their wicked power, jus=
t
> > > > don't give me.
>
> > > Ok. For me, prototyping means writing in a dynamic style without the =
benefit
> > > of a coherent design. OCaml is the only statically typed language tha=
t
> > > allows me to do that thanks to its very powerful inference. In contra=
st,
> > > Haskell has very weak inference.
>
> > > --
> > > Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy=
..com/?u
>
> > By the way, someone is posting on Clojure ML under "JoHn
> > Harrop" (singing praises to Clojure). So I have to ask, is that poster
> > an impostor?
>
> I've looked at some of JoHn Harrop's posts on the Clojure ML. He seems
> to be actively coding in Clojure, and in addition, seems to have some
> understanding of the Lisp Way. I think he just happens to have the
> same last name as our amphibian friend.

I think Lisp programmers (especially in comp.lang.lisp) like to
flatter themselves. They think others disagree with them because they
weren't smart enough to understand what needed to be understood.

"Lisp Way" is by far not the most complicated thing to understand.
OCaml is basically Scheme with static types. Camlp4 is dirty macros
for a more complicated syntax (if you grok the former, the latter are
trivial).

Whether it's better or worse is a totally separate question. IMHO
OCaml requires more brains though.
0
Reply fft1976 (100) 7/17/2009 1:49:09 AM

fft1976 wrote:
> I think Lisp programmers (especially in comp.lang.lisp) like to
> flatter themselves. They think others disagree with them because they
> weren't smart enough to understand what needed to be understood.

To be fair, a lot of clever people used to use Lisp before the modern FPLs
branched off.

Ironically, Lispers taunting C programmers about Greenspunning 20 years ago
has turned around to today's programmers trying to explain to Lispers why
it is not feasible for them to expect to Greenspun a decent pattern matcher
or concurrent garbage collector.

Multicore seems to have forced the issue though, and most Lispers are
jumping ship to Clojure even if it does use slightly different kinds of
superfluous parentheses. ;-)

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/17/2009 3:18:35 AM

On Jul 16, 8:18=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> fft1976 wrote:
> > I think Lisp programmers (especially in comp.lang.lisp) like to
> > flatter themselves. They think others disagree with them because they
> > weren't smart enough to understand what needed to be understood.
>
> To be fair, a lot of clever people used to use Lisp before the modern FPL=
s
> branched off.

I'm not saying Lispers are dumber than Ocamlers, just that the
concepts you need to learn to understand OCaml are almost a superset
of those needed to understand Lisp.
0
Reply fft1976 (100) 7/17/2009 3:40:50 AM

Jon Harrop wrote:
> Paul Rubin wrote:
>> Jon Harrop <jon@ffconsultancy.com> writes:
>>> First up, here are my timings for encoding a 5.5Mb copy of the bible:
>>> pbzip2:             ~1.0s
>>> bzip2:              ~1.5s
>>> My F#:               1.4s
>> 
>> Nice job!  However, how much of your time did you spend writing that
>> code, just to prove something that you already knew?
> 
> Took ~30mins to write but it completely shattered my prediction that F#
> would be considerably slower than C.

After a lot more optimization effort I have managed to create a much uglier
OCaml implementation that is still 10x slower than my F# and has had all
abstractions removed by hand because they incur such severe performance
overheads (my first OCaml port was 146x slower than F#!):

  open Bigarray
  
  type int_array = (int, int_elt, c_layout) Array1.t
  
  type byte_array = (int, int8_unsigned_elt, c_layout) Array1.t
  
  exception Cmp of int
  
  let cmp (str: byte_array) i j =
    let n = Array1.dim str in
    let i = ref i and j = ref j in
    try
      while true do
        if !i = n then raise(Cmp 1) else
          if !j = n then raise(Cmp(-1)) else
            let si = str.{!i} and sj = str.{!j} in
            if si < sj then raise(Cmp(-1)) else
              if si > sj then raise(Cmp 1) else
                begin
                  incr i;
                  incr j
                end
      done;
      0
    with Cmp c -> c
  
  let swap (a: int_array) i j =
    let t = a.{i} in
    a.{i} <- a.{j};
    a.{j} <- t
  
  let sort str (a: int_array) =
    let rec qsort l u =
      if l < u then
        begin
          swap a l ((l + u) / 2);
          let m = ref l in
          for i=l+1 to u do
            if cmp str a.{i} a.{l} < 0 then
              begin
                incr m;
                swap a !m i
              end
          done;
          swap a l !m;
          qsort l (!m - 1);
          qsort (!m + 1) u
        end in
    qsort 0 (Array1.dim a - 1)
  
  let () =
    let file = try Sys.argv.(1) with _ -> "input.txt" in
    let desc = Unix.openfile file [] 777 in
    let str = Array1.map_file desc int8_unsigned c_layout false (-1) in
    let n = Array1.dim str in
  
    let a = Array1.create int c_layout n in
    for i=0 to n-1 do
      a.{i} <- i
    done;
    sort str a;
    for i=0 to n-1 do
      print_char(Char.chr str.{(a.{i} + n - 1) mod n})
    done;
  
    Unix.close desc

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/17/2009 5:21:50 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> Stephen J. Bevan wrote:
>> Jon Harrop <jon@ffconsultancy.com> writes:
>>> Stephen J. Bevan wrote:
>>>> Jon Harrop <jon@ffconsultancy.com> writes:
>> The topic is your claim that :-
>> 
>>> Of course there is a sane reason! The *only* way you can justify the
>>> following claim is by crippling your hash table implementation:
>>>
>>>  "Compared to a hash table, a well-implemented purely functional tree
>>>  data
>>> structure will perform competitively. You should not approach trees with
>>> the assumption that your code will pay a performance penalty." - Real
>>> World Haskell
>> 
>> One does not have to cripple the hash table to justify the claim,
>
> Consider the task of filling your dictionary (hash table or purely
> functional tree) with ten million machine-precision integers. The only way
> you can possibly make a purely functional tree "perform competitively" is
> by crippling the hash table.

Rather than consider it I decided to measure it using a red-black tree :-

1  tree is 34x  faster than hash using fixed size table of size N/1000
2  tree is 3x   faster than hash using fixed size table of size N/100
3  tree is 2.3x slower than hash using fixed size table of size N/10
4  tree is 5-7x slower than hash using fixed size table of size N
5  tree is 3x   slower than hash using resizing table with start size of N/10

Note the quote is "perform competitively" which is why I tested
various values to show the best case and worst case performance.  The
worst case here is meant to simulate the type of problems with real
world programs reported in http://www.cs.rice.edu/~scrosby/hash/.

If one concentrates on best case performance then whether trees
"perform competitively" depends on whether one considers 2-7x
competitive.

If one concentrates on worst case performance then being 3-34x faster
is clearly competitive.

Note I wrote the tests in C to avoid GC issues but while the actual
ratios may vary a bit based on the language or the exact hash function
chosen (I used the hash that O'Caml uses for doubles) it is always
possible to produce an arbitrary bad result for a hash table by
inducing lots of collisions as I did in the first test.  Re-sizing or
using a balanced tree rather than linked list can cure the problem but
the former isn't always possible (locking the table too long) and the
latter uses a balanced tree which would contradict your claim.
0
Reply stephen104 (378) 7/17/2009 6:32:25 AM

Jon Harrop wrote:

> After a lot more optimization effort I have managed to create a much uglier
> OCaml implementation that is still 10x slower than my F# and has had all
> abstractions removed by hand because they incur such severe performance
> overheads (my first OCaml port was 146x slower than F#!):

Is this comparison being done on the same platform? Same machine?

Your Ocaml code uses the Unix module. I thought that wasn't available
on the windows version of Ocaml while I assume your F# code was
running on windows.

What gives?

Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/
0
Reply erikd (176) 7/17/2009 7:19:41 AM

On Jul 17, 5:40=A0am, fft1976 <fft1...@gmail.com> wrote:
> On Jul 16, 8:18=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>
> > fft1976 wrote:
> > > I think Lisp programmers (especially in comp.lang.lisp) like to
> > > flatter themselves. They think others disagree with them because they
> > > weren't smart enough to understand what needed to be understood.
>
> > To be fair, a lot of clever people used to use Lisp before the modern F=
PLs
> > branched off.
>
> I'm not saying Lispers are dumber than Ocamlers, just that the
> concepts you need to learn to understand OCaml are almost a superset
> of those needed to understand Lisp.

I don't agree with this. OCaml (and functional languages in general)
share with Lisp some concepts, but differ substantially in many
things. E.g. I can't expect someone to work with OCaml without
understanding type inference and pattern matching. You can use Lisp
just fine without knowing about those. Conversely, Lisp often forces
you to think in terms of abstract syntax (first class symbols,
macros), while OCaml does not. And Lisp has multimethods, etc. etc.

Of course whatever language you use you should have clear at least the
basic concepts from programming language theory, even if your language
of choice does not provide some of them natively. But this is
completely orthogonal to Lisp, OCaml, C, Java, or whatever.

Alessio
0
Reply alessiostalla (364) 7/17/2009 7:53:58 AM

Stephen J. Bevan wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> Stephen J. Bevan wrote:
>>> Jon Harrop <jon@ffconsultancy.com> writes:
>>>> Stephen J. Bevan wrote:
>>>>> Jon Harrop <jon@ffconsultancy.com> writes:
>>> The topic is your claim that :-
>>> 
>>>> Of course there is a sane reason! The *only* way you can justify the
>>>> following claim is by crippling your hash table implementation:
>>>>
>>>>  "Compared to a hash table, a well-implemented purely functional
>>>>  tree... 
>
> ...Note I wrote the tests in C...

Can you give us the code? I am particularly interested in your purely
functional tree implementation in C.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/17/2009 10:24:00 AM

Jon Harrop wrote:

> That comparison was 32-bit Debian with OCaml

Debian stable? testing? unstable? Ocaml version? Linux kernel
version? Filesystem?

Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/
0
Reply erikd (176) 7/17/2009 11:32:06 AM

Erik de Castro Lopo wrote:
> Jon Harrop wrote:
>> After a lot more optimization effort I have managed to create a much
>> uglier OCaml implementation that is still 10x slower than my F# and has
>> had all abstractions removed by hand because they incur such severe
>> performance overheads (my first OCaml port was 146x slower than F#!):
> 
> Is this comparison being done on the same platform? Same machine?

That comparison was 32-bit Debian with OCaml and 32-bit Windows Vista with
F#. The machine is a Dell Precision T5400 with two Intel Xeon E5405 2.0GHz
quadcores (i.e. 8 cores in total) and 4Gb RAM.

> Your Ocaml code uses the Unix module. I thought that wasn't available
> on the windows version of Ocaml while I assume your F# code was
> running on windows.

The Unix module and Bigarray work fine from the OCaml top-level on Windows
here but I've tried both the MSVC and MinGW installs of OCaml and cannot
get either to compile to native code.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/17/2009 12:05:01 PM

On Jul 16, 11:18=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>
> Multicore seems to have forced the issue though, and most Lispers are
> jumping ship to Clojure even if it does use slightly different kinds of
> superfluous parentheses. ;-)
>

This is a perfect example of the unsupported and content-free
assertions that have made you such an esteemed and popular member of
the Lisp community.
0
Reply larryliberty (26) 7/17/2009 12:18:16 PM

On Thu, 25 Jun 2009 06:53:41 -0700 (PDT), Pillsy <pillsbury@gmail.com>
wrote:

>On Jun 23, 6:23�pm, "!!!@!!!" <eltoni...@gmail.com> wrote:
>> I'm not trying to start a flame war about which one is the best. Could
>> anybody explain me each of these languages features and strong points ?
>
>Common Lisp is so much more useful than either Prolog or Haskell that
>it isn't even funny.
>

Then, why Lisp is dead?...

A.L.
0
Reply alewando9477 (47) 7/17/2009 12:27:07 PM

On Jul 16, 9:49=A0pm, fft1976 <fft1...@gmail.com> wrote:
> I think Lisp programmers (especially in comp.lang.lisp) like to
> flatter themselves. They think others disagree with them because they
> weren't smart enough to understand what needed to be understood.

I'm definitely no Lisp expert, but I have read ANSI Common Lisp and On
Lisp and seen enough to decide to start my next project in CL. BTW,
the tendency to conclude that people who disagree with you just don't
understand is a lot more prevalent than you may think.

>
> "Lisp Way" is by far not the most complicated thing to understand.

I never said (or meant to imply) that it was. It's actually quite
simple, but it requires letting go of your old ways if you came from
an imperative or object-oriented environment.

> OCaml is basically Scheme with static types.
> Camlp4 is dirty macros
> for a more complicated syntax (if you grok the former, the latter are
> trivial).
>
> Whether it's better or worse is a totally separate question. IMHO
> OCaml requires more brains though.

I'm not sure about this point. You can write imperative code in OCaml
and it won't complain or get in your way as long as the types are
correct. Lisp and Scheme will also let you write imperative code, but
anyone who sees it will make fun of you behind your back. Haskell
forces you to change.
0
Reply larryliberty (26) 7/17/2009 12:33:46 PM

Erik de Castro Lopo wrote:
> Jon Harrop wrote:
>> That comparison was 32-bit Debian with OCaml
> 
> Debian stable? testing? unstable?

Debian testing.

> Ocaml version?

3.11.0

> Linux kernel version?

$ uname -a
Linux leper 2.6.24-etchnhalf.1-amd64 #1 SMP Fri Dec 26 05:32:46 UTC 2008
x86_64 GNU/Linux

> Filesystem? 

Ext3.

However, I've found a perf bug in my parallelization of the OCaml code and
can now get a speedup for parallelism in OCaml. Specifically, the time
taken falls from 14s to 4s, which is only 2.9x slower than F#!

Here's my latest OCaml code:

  open Bigarray
  
  type int_array = (int, int_elt, c_layout) Array1.t
  
  type byte_array = (int, int8_unsigned_elt, c_layout) Array1.t
  
  exception Cmp of int
  
  let cmp (str: byte_array) i j =
    let n = Array1.dim str in
    let i = ref i and j = ref j in
    try
      while true do
        if !i = n then raise(Cmp 1) else
          if !j = n then raise(Cmp(-1)) else
            let si = str.{!i} and sj = str.{!j} in
            if si < sj then raise(Cmp(-1)) else
              if si > sj then raise(Cmp 1) else
                begin
                  incr i;
                  incr j
                end
      done;
      0
    with Cmp c -> c
  
  let swap (a: int_array) i j =
    let t = a.{i} in
    a.{i} <- a.{j};
    a.{j} <- t
  
  let invoke (f : 'a -> 'b) x : unit -> 'b =
    let input, output = Unix.pipe() in
    match Unix.fork() with
    | -1 -> (let v = f x in fun () -> v)
    | 0 ->
        Unix.close input;
        let output = Unix.out_channel_of_descr output in
        Marshal.to_channel output (try `Res(f x) with e -> `Exn e) [];
        close_out output;
        exit 0
    | pid ->
        Unix.close output;
        let input = Unix.in_channel_of_descr input in
        fun () ->
          let v = Marshal.from_channel input in
          ignore (Unix.waitpid [] pid);
          close_in input;
          match v with
          | `Res x -> x
          | `Exn e -> raise e;;
  
  let sort str (a: int_array) =
    let rec qsort l u =
      if l < u then
        begin
          swap a l ((l + u) / 2);
          let m = ref l in
          for i=l+1 to u do
            if cmp str a.{i} a.{l} < 0 then
              begin
                incr m;
                swap a !m i
              end
          done;
          swap a l !m;
          if u - l > 30000 then
            begin
              let f () =
                qsort l (!m - 1);
                Array1.sub a l (!m-l-1) in
              let a' = invoke f () in
              qsort (!m + 1) u;
              let a' = a'() in
              for i=l to !m-2 do
                a.{i} <- a'.{i - l}
              done
            end
          else
            begin
              qsort l (!m - 1);
              qsort (!m + 1) u
            end
        end in
    ignore(qsort 0 (Array1.dim a - 1))
  
  let () =
    let file = try Sys.argv.(1) with _ -> "input.txt" in
    let desc = Unix.openfile file [] 777 in
    let str = Array1.map_file desc int8_unsigned c_layout false (-1) in
    let n = Array1.dim str in
  
    let a = Array1.create int c_layout n in
    for i=0 to n-1 do
      a.{i} <- i
    done;
    sort str a;
    for i=0 to n-1 do
      print_char(Char.chr str.{(a.{i} + n - 1) mod n})
    done;
  
    Unix.close desc

To be fair, I've optimized the comparison function in the OCaml but not in
the F# now...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/17/2009 1:00:37 PM

Larry Coleman wrote:
> On Jul 16, 11:18 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Multicore seems to have forced the issue though, and most Lispers are
>> jumping ship to Clojure even if it does use slightly different kinds of
>> superfluous parentheses. ;-)
> 
> This is a perfect example of the unsupported and content-free
> assertions that have made you such an esteemed and popular member of
> the Lisp community.

Esteemed indeed. Here's some "content" though:

  http://www.google.com/trends?q=common+lisp%2Cclojure

You have to admit, Rich Hickey is doing a bloody good job getting Clojure
off the ground.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/17/2009 1:38:42 PM

A.L. wrote:
> Then, why Lisp is dead?...

Lisp isn't dead. Its undead!

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/17/2009 1:39:30 PM

On Jul 17, 8:27=A0am, A.L. <alewa...@aol.com> wrote:

> On Thu, 25 Jun 2009 06:53:41 -0700 (PDT), Pillsy <pillsb...@gmail.com>
> wrote:

> >On Jun 23, 6:23=A0pm, "!!!@!!!" <eltoni...@gmail.com> wrote:

> >> I'm not trying to start a flame war about which one is the best. Could
> >> anybody explain me each of these languages features and strong points =
?

> >Common Lisp is so much more useful than either Prolog or Haskell that
> >it isn't even funny.

> Then, why Lisp is dead?...

I blame the breakdown in the educational system that left you unable
to read for comprehension.

Later,
Pillsy
0
Reply pillsbury (453) 7/17/2009 2:27:13 PM

On Jul 17, 6:24 am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Stephen J. Bevan wrote:
> > Jon Harrop <j...@ffconsultancy.com> writes:
> >> Stephen J. Bevan wrote:
> >>> Jon Harrop <j...@ffconsultancy.com> writes:
> >>>> Stephen J. Bevan wrote:
> >>>>> Jon Harrop <j...@ffconsultancy.com> writes:
> >>> The topic is your claim that :-
>
> >>>> Of course there is a sane reason! The *only* way you can justify the
> >>>> following claim is by crippling your hash table implementation:
>
> >>>>  "Compared to a hash table, a well-implemented purely functional
> >>>>  tree...
>
> > ...Note I wrote the tests in C...
>
> Can you give us the code? I am particularly interested in your purely
> functional tree implementation in C.

Yes me too. Stephen, please provide the code. I very much want
to see the purely functional tree implementation in C as well.
Thanks in advance!

KHD
0
Reply duggar (292) 7/17/2009 7:42:22 PM

Keith H Duggar <duggar@alum.mit.edu> writes:
> Yes me too. Stephen, please provide the code. I very much want
> to see the purely functional tree implementation in C as well.
> Thanks in advance!

http://www.google.com/search?q=red-black+tree+c

works for me.
0
Reply phr.cx (5483) 7/17/2009 8:08:36 PM

Paul Rubin wrote:
> Keith H Duggar <duggar@alum.mit.edu> writes:
>> Yes me too. Stephen, please provide the code. I very much want
>> to see the purely functional tree implementation in C as well.
>> Thanks in advance!
> 
> http://www.google.com/search?q=red-black+tree+c
> 
> works for me.

That looks imperative and not purely functional to me.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/18/2009 12:17:46 AM

On Fri, 17 Jul 2009 05:33:46 -0700, Larry Coleman wrote:

> I'm not sure about this point. You can write imperative code in OCaml
> and it won't complain or get in your way as long as the types are
> correct. Lisp and Scheme will also let you write imperative code, but
> anyone who sees it will make fun of you behind your back. Haskell
> forces you to change.

You're free to write imperative code in Haskell. You need to put "IO"
in front of all of your return types, the syntax for reading and
writing mutable variables is more verbose than most languages, and
creating global mutable variables requires some minor hackery. But there
isn't really anything which is actually missing.

0
Reply nobody (4804) 7/18/2009 12:26:23 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> Asymptotically efficient mutable data structures (arrays, hash tables),
> predictable performance, predictable latency, predictable memory
> consumption, reflection, JIT compilation and some solution for factoring
> large code bases (modules or objects) are all missing from Haskell.

STUArray is asymptotically efficient.  There is an open bug related to
STArray and garbage collection as has been discussed here, though it
doesn't seem to bother many applications in practice.  Hash tables are
evil for programmers care about worst case performance.  Programmers
who don't care about worst case performance are often being naive.  No
language with garbage collection has really predictable memory
consumption or latency.  There is a Haskell DSL (Atom) for writing
real-time applications with constant storage and predictable latency.
The real-time operations are expressed as, you guessed it, monadic
actions.

Haskell's module and typeclass system is equivalent to ML's module and
functor system, but more convenient a lot of the time.  I don't
understand why anyone wants JIT compilation instead of ahead-of-time
compilation.  (Staged compilation is something else).  The highest
performance ML compiler is MLTon (whole-program compilation) and the
bleeding edge Haskell approaches (JHC, Supero) are even more like
that.  Haskell has enough reflection to support SYB generics, and
extensions have been made for full blown genericity (Generic Haskell).

For a language with fine grained control over mutable structures in a
strongly typed setting, ATS ( http://www.ats-lang.org ) looks pretty
interesting.  I don't think ML or Haskell comes anywhere near it in
expressiveness.
0
Reply phr.cx (5483) 7/18/2009 1:32:14 AM

Larry Coleman wrote:
> I'm not sure about this point. You can write imperative code in OCaml
> and it won't complain or get in your way as long as the types are
> correct. Lisp and Scheme will also let you write imperative code, but
> anyone who sees it will make fun of you behind your back. Haskell
> forces you to change.

Writing imperative code is a critically-important part of using impure
functional languages because purely functional programming is incapable of
solving practically-important problems.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/18/2009 1:50:12 AM

Nobody wrote:
> On Fri, 17 Jul 2009 05:33:46 -0700, Larry Coleman wrote:
>> I'm not sure about this point. You can write imperative code in OCaml
>> and it won't complain or get in your way as long as the types are
>> correct. Lisp and Scheme will also let you write imperative code, but
>> anyone who sees it will make fun of you behind your back. Haskell
>> forces you to change.
> 
> You're free to write imperative code in Haskell. You need to put "IO"
> in front of all of your return types, the syntax for reading and
> writing mutable variables is more verbose than most languages, and
> creating global mutable variables requires some minor hackery. But there
> isn't really anything which is actually missing.

Asymptotically efficient mutable data structures (arrays, hash tables),
predictable performance, predictable latency, predictable memory
consumption, reflection, JIT compilation and some solution for factoring
large code bases (modules or objects) are all missing from Haskell.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/18/2009 2:01:37 AM

On Jul 17, 4:08 pm, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> Keith H Duggar <dug...@alum.mit.edu> writes:
>
> > Yes me too. Stephen, please provide the code. I very much want
> > to see the purely functional tree implementation in C as well.
> > Thanks in advance!
>
> http://www.google.com/search?q=red-black+tree+c
>
> works for me.

Your post indicates that you either

1) ignored the "purely functional" qualifier

2) incorrectly interpreted "purely functional" to mean
   "functions properly"

3) you believe that those implementations are "purely
   functional"

4) you believe that any "purely functional" implementation
   will do if we happen to find one

5) believe we are morons

Which is it? 1) would mean you need to read more carefully and
try to genuinely understand what what you read before responding.
In the case of 2), please understand that "purely functional"
means "functional" in the comp.lang.functional programming
sense. If 3) then I would suggest you look again at the search
results to see they are not purely functional or post a specific
link to what you consider a "purely functional" implementation.
As to 4), we need Stephen's implementation since he made a claim
specifically about his implementation. 5) is unproductive and
would show you to be acting like a jerk.

I hope it is 2) or 4) but I'm not very optimistic.

KHD
0
Reply duggar (292) 7/18/2009 2:47:18 AM

Paul Rubin wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> Asymptotically efficient mutable data structures (arrays, hash tables),
>> predictable performance, predictable latency, predictable memory
>> consumption, reflection, JIT compilation and some solution for factoring
>> large code bases (modules or objects) are all missing from Haskell.
> 
> STUArray is asymptotically efficient.  There is an open bug related to
> STArray and garbage collection as has been discussed here, though it
> doesn't seem to bother many applications in practice.

Haskell users have been complaining about it publicly for at least 6 years.

> Hash tables are evil for programmers care about worst case performance.

Hash tables can support constant time insertion, deletion and lookup.

> Programmers who don't care about worst case performance are often being
> naive.

Yet those programmers successfully sell software whereas Haskell programmers
cannot even give theirs away for free.

> No language with garbage collection has really predictable memory
> consumption or latency.

The JVM and CLR are good enough for desktop GUI apps and even games. GHC's
stop-the-world GC is not.

> Haskell's module and typeclass system is equivalent to ML's module and
> functor system, but more convenient a lot of the time.

Not "equivalent" enough for Lennart Augustsson, author of the world's first
Haskell compiler:

  http://augustss.blogspot.com/2008_12_01_archive.html

> I don't understand why anyone wants JIT compilation instead of
> ahead-of-time compilation. 

Either would be nice.

> The highest performance ML compiler is MLTon

A famous counter example:

  http://www.ffconsultancy.com/languages/ray_tracer/results.html

> bleeding edge Haskell approaches (JHC, Supero) are even more like
> that.

They take a major problem in Haskell (unpredictable performance) and make it
worse.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/18/2009 4:33:37 AM

On Jul 17, 9:50=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > I'm not sure about this point. You can write imperative code in OCaml
> > and it won't complain or get in your way as long as the types are
> > correct. Lisp and Scheme will also let you write imperative code, but
> > anyone who sees it will make fun of you behind your back. Haskell
> > forces you to change.
>
> Writing imperative code is a critically-important part of using impure
> functional languages because purely functional programming is incapable o=
f
> solving practically-important problems.
>
That's a strong claim and could do with some clarification. What would
you consider to be a pure functional programming language?

What counts as a "practically-important problem"? One thing I have to
do at work is update stored procedures that archive our production
database. I had to manually verify that each table and column was
being archived, and that all tables that referenced archived tables
were also archived. The process was tedious and error-prone. The
program that I wrote in Haskell solved this problem. Does that count?

Once you've clarified those two points, I'd be interested to know how
you could prove that purely functional programming is incapable of
solving "practically-important problems" as you will have defined
them. Or maybe not. It will depend on your definitions.

Nice use of the straw man, BTW. I was really only questioning
fft1976's statement that OCaml requires more brains by making the
point that it doesn't if you only write imperative code in it.

0
Reply larryliberty (26) 7/18/2009 11:26:05 AM

In comp.lang.haskell Keith H Duggar <duggar@alum.mit.edu> wrote:
> On Jul 17, 4:08 pm, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
>> Keith H Duggar <dug...@alum.mit.edu> writes:

>> > Yes me too. Stephen, please provide the code. I very much want
>> > to see the purely functional tree implementation in C as well.
>> > Thanks in advance!

>> http://www.google.com/search?q=red-black+tree+c

>> works for me.

> Your post indicates that you either

> 1) ignored the "purely functional" qualifier
> 
> 2) incorrectly interpreted "purely functional" to mean
>   "functions properly"

What, exactly, does "purely functional" mean in the context of functional
programming languages?  What would a piece of haskell have to look like
to fail to be "purely functional"?  Is it possible at all for a piece of
C to be "purely functional", and if so, how?

> 3) you believe that those implementations are "purely
>   functional"

> 4) you believe that any "purely functional" implementation
>   will do if we happen to find one

[ .... ]

> Which is it? 1) would mean you need to read more carefully and
> try to genuinely understand what what you read before responding.
> In the case of 2), please understand that "purely functional"
> means "functional" in the comp.lang.functional programming
> sense.

Maybe I'm misunderstanding, but I always thought that "functional"
programmnig was more of a stylistic emphasis, rather than a rigid
definition - calculating functions: good - setting variables and
specifying procedural aspects: considered harmful.  If so, there won't
be any rigid definition.

[ .... ]

> KHD

-- 
Alan Mackenzie (Nuremberg, Germany).

0
Reply acm (248) 7/18/2009 1:44:32 PM

On Sat, 18 Jul 2009 03:01:37 +0100, Jon Harrop wrote:

>> You're free to write imperative code in Haskell. You need to put "IO"
>> in front of all of your return types, the syntax for reading and
>> writing mutable variables is more verbose than most languages, and
>> creating global mutable variables requires some minor hackery. But there
>> isn't really anything which is actually missing.
> 
> Asymptotically efficient mutable data structures (arrays, hash tables),
> predictable performance, predictable latency, predictable memory
> consumption, reflection, JIT compilation and some solution for factoring
> large code bases (modules or objects) are all missing from Haskell.

Name an imperative language which has all of those. The low-level ones
have the first few but not the last, the high-level ones have the last at
the expense of the first.

0
Reply nobody (4804) 7/18/2009 7:24:11 PM

Alan Mackenzie wrote:
> Maybe I'm misunderstanding, but I always thought that "functional"
> programmnig was more of a stylistic emphasis, rather than a rigid
> definition - calculating functions: good - setting variables and
> specifying procedural aspects: considered harmful.  If so, there won't
> be any rigid definition.

Read "Purely functional data structures" by Chris Okasaki.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/19/2009 2:16:41 AM

Nobody wrote:
> On Sat, 18 Jul 2009 03:01:37 +0100, Jon Harrop wrote:
>>> You're free to write imperative code in Haskell. You need to put "IO"
>>> in front of all of your return types, the syntax for reading and
>>> writing mutable variables is more verbose than most languages, and
>>> creating global mutable variables requires some minor hackery. But there
>>> isn't really anything which is actually missing.
>> 
>> Asymptotically efficient mutable data structures (arrays, hash tables),
>> predictable performance, predictable latency, predictable memory
>> consumption, reflection, JIT compilation and some solution for factoring
>> large code bases (modules or objects) are all missing from Haskell.
> 
> Name an imperative language which has all of those. The low-level ones
> have the first few but not the last, the high-level ones have the last at
> the expense of the first.

Java, C#, VB and F# have sufficient support for all of those features that
they can be used to solve real problems even where they are relied upon
(e.g. games).

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/19/2009 2:19:16 AM

Larry Coleman wrote:
> On Jul 17, 9:50 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Larry Coleman wrote:
>> > I'm not sure about this point. You can write imperative code in OCaml
>> > and it won't complain or get in your way as long as the types are
>> > correct. Lisp and Scheme will also let you write imperative code, but
>> > anyone who sees it will make fun of you behind your back. Haskell
>> > forces you to change.
>>
>> Writing imperative code is a critically-important part of using impure
>> functional languages because purely functional programming is incapable
>> of solving practically-important problems.
>
> That's a strong claim and could do with some clarification. What would
> you consider to be a pure functional programming language?

Haskell.

> What counts as a "practically-important problem"?

The BWT challenge.

> One thing I have to 
> do at work is update stored procedures that archive our production
> database. I had to manually verify that each table and column was
> being archived, and that all tables that referenced archived tables
> were also archived. The process was tedious and error-prone. The
> program that I wrote in Haskell solved this problem. Does that count?

Yes.

> Once you've clarified those two points, I'd be interested to know how
> you could prove that purely functional programming is incapable of
> solving "practically-important problems" as you will have defined
> them. Or maybe not. It will depend on your definitions.

By counter example. I've yet to see a BWT written in Haskell that can
compress 20Mb of data on my 4Gb machine without running out of RAM, let
alone get within a few times the performance of C.

Just to clarify, I'm not talking about "Haskell" that is just C code written
using the FFI and/or unsafe features. Frag was once hailed as an example of
Haskell being relevant to games programming but the code just segfaulted on
my 64-bit machine because it wasn't really written in Haskell (because real
Haskell was unusably slow).

> Nice use of the straw man, BTW. I was really only questioning
> fft1976's statement that OCaml requires more brains by making the
> point that it doesn't if you only write imperative code in it.

That is a circular truism that applies to all languages including Haskell.
Except perhaps that Haskell requires less brains because you can do less
with it.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/19/2009 2:30:36 AM

On Jul 18, 10:30=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > On Jul 17, 9:50=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> >> Larry Coleman wrote:
> >> > I'm not sure about this point. You can write imperative code in OCam=
l
> >> > and it won't complain or get in your way as long as the types are
> >> > correct. Lisp and Scheme will also let you write imperative code, bu=
t
> >> > anyone who sees it will make fun of you behind your back. Haskell
> >> > forces you to change.
>
> >> Writing imperative code is a critically-important part of using impure
> >> functional languages because purely functional programming is incapabl=
e
> >> of solving practically-important problems.
>
> > That's a strong claim and could do with some clarification. What would
> > you consider to be a pure functional programming language?
>
> Haskell.
>
> > What counts as a "practically-important problem"?
>
> The BWT challenge.
>
> > One thing I have to
> > do at work is update stored procedures that archive our production
> > database. I had to manually verify that each table and column was
> > being archived, and that all tables that referenced archived tables
> > were also archived. The process was tedious and error-prone. The
> > program that I wrote in Haskell solved this problem. Does that count?
>
> Yes.
>

So you've admitted that a practical problem has been solved using
Haskell. I assume that next you'll demand that I provide a copy of the
code and imply that I'm lying if I won't or can't.

> > Once you've clarified those two points, I'd be interested to know how
> > you could prove that purely functional programming is incapable of
> > solving "practically-important problems" as you will have defined
> > them. Or maybe not. It will depend on your definitions.
>
> By counter example. I've yet to see a BWT written in Haskell that can
> compress 20Mb of data on my 4Gb machine without running out of RAM, let
> alone get within a few times the performance of C.

Did someone sleep through Philosophy 101?

If you had been alive in 1900, you might have said: "I'll prove that
heavier-than-air flight is impossible by counter-example. I've yet to
see a glider with attached propellers that flew successfully. QED."

>
> Just to clarify, I'm not talking about "Haskell" that is just C code writ=
ten
> using the FFI and/or unsafe features. Frag was once hailed as an example =
of
> Haskell being relevant to games programming but the code just segfaulted =
on
> my 64-bit machine because it wasn't really written in Haskell (because re=
al
> Haskell was unusably slow).
>
> > Nice use of the straw man, BTW. I was really only questioning
> > fft1976's statement that OCaml requires more brains by making the
> > point that it doesn't if you only write imperative code in it.
>
> That is a circular truism that applies to all languages including Haskell=
..
> Except perhaps that Haskell requires less brains because you can do less
> with it.
>

Your unrequited love for Lisp and Haskell is now common knowledge. The
game's basically up, but you can probably still harass the newbies.


0
Reply larryliberty (26) 7/19/2009 9:41:49 AM

Larry Coleman wrote:
> If you had been alive in 1900, you might have said: "I'll prove that
> heavier-than-air flight is impossible by counter-example. I've yet to
> see a glider with attached propellers that flew successfully. QED."

You have been civil until now so I'm going to give you the benefit of the
doubt and assume that you just misunderstood my statement.

I was saying that it is not possible to solve important practical problems
(a usable BWT being one example) using purely functional programming and,
consequently, impure programming is an essential part of using most
functional languages.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/19/2009 11:08:53 AM

On Jul 19, 7:08=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > If you had been alive in 1900, you might have said: "I'll prove that
> > heavier-than-air flight is impossible by counter-example. I've yet to
> > see a glider with attached propellers that flew successfully. QED."
>
> You have been civil until now so I'm going to give you the benefit of the
> doubt and assume that you just misunderstood my statement.

I understood your statement as well as could be expected given that
it's slightly ambiguous. It could be read as "there are some practical
problems that purely functional programming cannot solve" or it could
be read as "purely functional programming cannot solve any practical
problem."

If I stopped being civil, it's because I expect that someone who uses
the letters "Dr" in front of his name should know what does or does
not constitute a valid proof. I should not have let the fact that you
obviously don't know what a valid proof is cause me to be uncivil, and
for that I apologize.

>
> I was saying that it is not possible to solve important practical problem=
s
> (a usable BWT being one example) using purely functional programming and,
> consequently, impure programming is an essential part of using most
> functional languages.
>
Yes, that's what you said last time. I asked for proof and am still
waiting.

If you do have such a proof, it would be worthwhile reading for
readers of any of the groups to which this thread was posted, and
would enhance Computer Science in general. I suspect that you don't
have such a proof, and therefore will not waste any more time on this
thread unless something changes.

0
Reply larryliberty (26) 7/19/2009 2:28:29 PM

Larry Coleman wrote:
> On Jul 19, 7:08 am, Jon Harrop <j...@ffconsultancy.com> wrote:
>> Larry Coleman wrote:
>> > If you had been alive in 1900, you might have said: "I'll prove that
>> > heavier-than-air flight is impossible by counter-example. I've yet to
>> > see a glider with attached propellers that flew successfully. QED."
>>
>> You have been civil until now so I'm going to give you the benefit of the
>> doubt and assume that you just misunderstood my statement.
> 
> I understood your statement as well as could be expected given that
> it's slightly ambiguous. It could be read as "there are some practical
> problems that purely functional programming cannot solve" or it could
> be read as "purely functional programming cannot solve any practical
> problem."
>
> If I stopped being civil, it's because I expect that someone who uses
> the letters "Dr" in front of his name should know what does or does
> not constitute a valid proof. I should not have let the fact that you
> obviously don't know what a valid proof is cause me to be uncivil, and
> for that I apologize.
> 
>> I was saying that it is not possible to solve important practical
>> problems (a usable BWT being one example) using purely functional
>> programming and, consequently, impure programming is an essential part of
>> using most functional languages.
>>
> Yes, that's what you said last time. I asked for proof and am still
> waiting.
> 
> If you do have such a proof, it would be worthwhile reading for
> readers of any of the groups to which this thread was posted, and
> would enhance Computer Science in general. I suspect that you don't
> have such a proof, and therefore will not waste any more time on this
> thread unless something changes.

Congratulations! That is probably the most inventive cop-out I have ever
seen.

When you're asking venture capitalists for funding and they request a
business plan, do you demand that they prove that your idea cannot make
money whilst insulting their credentials too?

There is, of course, no relevant notion of "proof" in this context so I
obviously cannot provide a proof. Nor did I ever pretend to be able to. Nor
is it of any relevance.

Best of luck though getting your PhD in "implementing a usable quicksort in
Haskell". Or BWT. Or LZW. Or...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/19/2009 3:58:59 PM

On Jul 19, 11:58=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > On Jul 19, 7:08=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> >> Larry Coleman wrote:
> >> > If you had been alive in 1900, you might have said: "I'll prove that
> >> > heavier-than-air flight is impossible by counter-example. I've yet t=
o
> >> > see a glider with attached propellers that flew successfully. QED."
>
> >> You have been civil until now so I'm going to give you the benefit of =
the
> >> doubt and assume that you just misunderstood my statement.
>
> > I understood your statement as well as could be expected given that
> > it's slightly ambiguous. It could be read as "there are some practical
> > problems that purely functional programming cannot solve" or it could
> > be read as "purely functional programming cannot solve any practical
> > problem."
>
> > If I stopped being civil, it's because I expect that someone who uses
> > the letters "Dr" in front of his name should know what does or does
> > not constitute a valid proof. I should not have let the fact that you
> > obviously don't know what a valid proof is cause me to be uncivil, and
> > for that I apologize.
>
> >> I was saying that it is not possible to solve important practical
> >> problems (a usable BWT being one example) using purely functional
> >> programming and, consequently, impure programming is an essential part=
 of
> >> using most functional languages.
>
> > Yes, that's what you said last time. I asked for proof and am still
> > waiting.
>
> > If you do have such a proof, it would be worthwhile reading for
> > readers of any of the groups to which this thread was posted, and
> > would enhance Computer Science in general. I suspect that you don't
> > have such a proof, and therefore will not waste any more time on this
> > thread unless something changes.
>
> Congratulations! That is probably the most inventive cop-out I have ever
> seen.
>
> When you're asking venture capitalists for funding and they request a
> business plan, do you demand that they prove that your idea cannot make
> money whilst insulting their credentials too?
>
> There is, of course, no relevant notion of "proof" in this context so I
> obviously cannot provide a proof. Nor did I ever pretend to be able to. N=
or
> is it of any relevance.
>
> Best of luck though getting your PhD in "implementing a usable quicksort =
in
> Haskell". Or BWT. Or LZW. Or...
>
> --
> Dr Jon D Harrop, Flying Frog Consultancy Ltd.http://www.ffconsultancy.com=
/?u

"Ridiculous claim"
"You don't have proof"
"Asking me for proof is a cop out"

Toot toot, troll train rolling into station.

--
Dr. A.C.L, Troll Train Consulting.
0
Reply anonymous.c.lisper (176) 7/19/2009 6:41:19 PM

In comp.lang.haskell Jon Harrop <jon@ffconsultancy.com> wrote:
> Alan Mackenzie wrote:
>> Maybe I'm misunderstanding, but I always thought that "functional"
>> programmnig was more of a stylistic emphasis, rather than a rigid
>> definition - calculating functions: good - setting variables and
>> specifying procedural aspects: considered harmful.  If so, there won't
>> be any rigid definition.

> Read "Purely functional data structures" by Chris Okasaki.

Hmm.  By some strange coincidence, that book doesn't seem to be on my
bookshelf.

Quick excursion via Google.  It seems what Dr. Okasaki is talking about
in his texts is not data structures which, in some sense, are purely
functional - it's about using bog standard data structures in languages
(such as as ML and Haskell) which are functional, to whatever degree of
purity.  Compressing phrases with prepositions and relative pronouns into
sequences of adjectives and nouns often doesn't work too well in English
(as contrasted to German, where it's usually OK).

Which has got precisely what to do with the recent flame fest?  Probably
not a lot.  Which might be generically similar to what the flame fest had
to do with.  Or more precisely, people using arcane terminology talking
crossly at cross purposes with eachother, because they tacitly disagree
about what the words mean.  Maybe.

Now given the disadvantages of programming in C (I'm sure we'd agree
they're substantial), why would anybody want to add the additional
handicap of doing things "purely functionally" in C?  If you're going to
accept the shackles of "pure functionalness", you'd be crazy to do it
in a language where you don't get back more than it costs.

-- 
Alan Mackenzie (Nuremberg, Germany).

0
Reply acm (248) 7/19/2009 6:51:08 PM

Jon Harrop <jon@ffconsultancy.com> writes:
> I was saying that it is not possible to solve important practical
> problems (a usable BWT being one example) using purely functional
> programming and, consequently, impure programming is an essential
> part of using most functional languages.

I would say that real-time programming is a more important practical
problem that's difficult to handle with functional languages
(including Lisp and *ML) than BWT.  There exist some problems FPL's
are not particularly suited to.  Real-time programming is one.  It's
conceivable (though dubious) that BWT is another.  If you study any
logic, you should know that "there exist" and "for all" are not the
same thing.  The idea is that we as programmers, to some extent,
actually tend to be involved in specific problem classes and use the
appropriate tools for them.  We don't care so much about issues
related to problems that we're not working on.

GHC certainly supports various impure constructions, e.g. STUArray,
the seq combinator, and so forth.  And in practical terms, Alioth
shows that for quite a few practical problems, GHC beats Ocaml and F#
rather soundly and is at least competitive in pretty much all.  If you
think BWT is so bloody important, maybe you should suggest that they
add it to the benchmarks.

Uvector.Algorithms contains a nice Haskell quicksort implementation,
by the way.
0
Reply phr.cx (5483) 7/19/2009 7:04:35 PM

On Jul 19, 5:41 am, Larry Coleman <larrylibe...@yahoo.com> wrote:
> On Jul 18, 10:30 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> > Larry Coleman wrote:
> > > On Jul 17, 9:50 pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> > >> Larry Coleman wrote:
> > >> > I'm not sure about this point. You can write imperative code in OCaml
> > >> > and it won't complain or get in your way as long as the types are
> > >> > correct. Lisp and Scheme will also let you write imperative code, but
> > >> > anyone who sees it will make fun of you behind your back. Haskell
> > >> > forces you to change.
>
> > >> Writing imperative code is a critically-important part of using impure
> > >> functional languages because purely functional programming is incapable
> > >> of solving practically-important problems.
>
> > > That's a strong claim and could do with some clarification. What would
> > > you consider to be a pure functional programming language?
>
> > Haskell.
>
> > > What counts as a "practically-important problem"?
>
> > The BWT challenge.
>
> > > One thing I have to
> > > do at work is update stored procedures that archive our production
> > > database. I had to manually verify that each table and column was
> > > being archived, and that all tables that referenced archived tables
> > > were also archived. The process was tedious and error-prone. The
> > > program that I wrote in Haskell solved this problem. Does that count?
>
> > Yes.
>
> So you've admitted that a practical problem has been solved using
> Haskell. I assume that next you'll demand that I provide a copy of the
> code and imply that I'm lying if I won't or can't.
>
> > > Once you've clarified those two points, I'd be interested to know how
> > > you could prove that purely functional programming is incapable of
> > > solving "practically-important problems" as you will have defined
> > > them. Or maybe not. It will depend on your definitions.
>
> > By counter example. I've yet to see a BWT written in Haskell that can
> > compress 20Mb of data on my 4Gb machine without running out of RAM, let
> > alone get within a few times the performance of C.
>
> Did someone sleep through Philosophy 101?

Did someone sleep through Logic and Discourse 101?

First, it's patently obvious from context and his answer to your
question that by

   "functional languages because purely functional programming is
   incapable of solving practically-important problems."

Jon means

   EXISTS[x](
     PraticallyImportant(x) AND
     FunctionalLanguagesIncapableSolving(x) )

not

   FORALL[x](
     NOT(PraticallyImportant(x)) OR (
        PraticallyImportant(x) AND
        !FunctionalLanguagesIncapableSolving(x) ) )

therefore your database problem was simply irrelevant to his claim.

Secondly, when a statement is ambiguous, a clarification request
and/or generous interpretation is important for efficient dialectic.
Therefore, when you interpreted

Jon Harrop wrote:
> Writing imperative code is a critically-important part of using impure
> functional languages because purely functional programming is incapable
> of solving practically-important problems.

You should have 1) asked for clarification or 2) interpreted
generously as

   "Writing imperative code is a critically-important part of using
   impure functional languages [in practice today] because purely
   functional programming [has so far been] incapable of solving
   [some] practically-important problems."

rather than trotting out burden of proof fallacy non-sense

   http://en.wikipedia.org/wiki/Burden_of_proof_(logical_fallacy)

over the truth of FunctionalLanguagesIncapableSolving(x).

Now, GOTO 10 and CONTINUE ...

KHD
0
Reply duggar (292) 7/19/2009 9:11:26 PM

On Jul 19, 5:11 pm, Keith H Duggar <dug...@alum.mit.edu> wrote:
> On Jul 19, 5:41 am, Larry Coleman <larrylibe...@yahoo.com> wrote:
> First, it's patently obvious from context and his answer to your
> question that by
>
>    "functional languages because purely functional programming is
>    incapable of solving practically-important problems."
>
> Jon means
>
>    EXISTS[x](
>      PraticallyImportant(x) AND
>      FunctionalLanguagesIncapableSolving(x) )
>
> not
>
>    FORALL[x](
>      NOT(PraticallyImportant(x)) OR (
>         PraticallyImportant(x) AND
>         !FunctionalLanguagesIncapableSolving(x) ) )

There is a typo in the FORALL clause. It should be

   FORALL[x](
     NOT(PraticallyImportant(x)) OR (
        PraticallyImportant(x) AND
        FunctionalLanguagesIncapableSolving(x) ) )

and if someone was thinking of attacking that typo and jumping
around in circles of joy, grow up.

KHD
0
Reply duggar (292) 7/19/2009 9:17:32 PM

Alan Mackenzie <acm@muc.de> writes:

> Quick excursion via Google.  It seems what Dr. Okasaki is talking about
> in his texts is not data structures which, in some sense, are purely
> functional - it's about using bog standard data structures in languages
> (such as as ML and Haskell) which are functional, to whatever degree of
> purity.

The algorithms for operating upon the data structures are the purely
functional part. (The fine details of the data structure design may vary
depending on how the algorithms need to work with them, of course.)

(snip)
> Which has got precisely what to do with the recent flame fest?

The question of if the purely functional tree implementation in C really
was using purely functional algorithms. A tree implementation tends to
include algorithms for finding, inserting, removing data, etc.

> Now given the disadvantages of programming in C (I'm sure we'd agree
> they're substantial), why would anybody want to add the additional
> handicap of doing things "purely functionally" in C?

To test the conjecture that, compared to a hash table, a
well-implemented purely functional tree data structure will perform
competitively?

Mark
0
Reply Mark.Carroll (154) 7/19/2009 10:02:14 PM

On Jul 19, 4:30=A0am, Jon Harrop <j...@ffconsultancy.com> wrote:
> Larry Coleman wrote:
> > On Jul 17, 9:50=A0pm, Jon Harrop <j...@ffconsultancy.com> wrote:
> >> Larry Coleman wrote:
> >> > I'm not sure about this point. You can write imperative code in OCam=
l
> >> > and it won't complain or get in your way as long as the types are
> >> > correct. Lisp and Scheme will also let you write imperative code, bu=
t
> >> > anyone who sees it will make fun of you behind your back. Haskell
> >> > forces you to change.
>
> >> Writing imperative code is a critically-important part of using impure
> >> functional languages because purely functional programming is incapabl=
e
> >> of solving practically-important problems.
>
> > That's a strong claim and could do with some clarification. What would
> > you consider to be a pure functional programming language?
>
> Haskell.
>
> > What counts as a "practically-important problem"?
>
> The BWT challenge.

If I understand correctly, the problem with that algorithm in Haskell
is that in Haskell array update is O(n), right?

If that's the case, I suppose that Clean admits a reasonably efficient
implementation of that algorithm without using too much black magic.


0
Reply vend82 (230) 7/19/2009 10:29:33 PM

On Sun, 19 Jul 2009 03:19:16 +0100, Jon Harrop wrote:

>>> Asymptotically efficient mutable data structures (arrays, hash tables),
>>> predictable performance, predictable latency, predictable memory
>>> consumption, reflection, JIT compilation and some solution for factoring
>>> large code bases (modules or objects) are all missing from Haskell.
>> 
>> Name an imperative language which has all of those. The low-level ones
>> have the first few but not the last, the high-level ones have the last at
>> the expense of the first.
> 
> Java, C#, VB and F# have sufficient support for all of those features that
> they can be used to solve real problems even where they are relied upon
> (e.g. games).

Anything with gc takes a hit on the first 3. They may be good enough for
some purposes, but they aren't for others.

If you need hard real-time with sub-millisecond latency, malloc/free is
out, as is accessing any code or data which isn't mlock()d. Obviously
Haskell doesn't cut it on that front, but nor do the other languages which
you cite.

As for how it compares to other languages, worst-case latency is largely a
question of how aggressive the gc is. And Haskell's memory consumption
isn't truly unpredictable, it just tends to throw some surprises if you
aren't paying attention. But that's true (albeit to a lesser extent) of
most languages which use gc.

0
Reply nobody (4804) 7/19/2009 10:56:12 PM

Vend <vend82@virgilio.it> writes:
> > The BWT challenge.
> If I understand correctly, the problem with that algorithm in Haskell
> is that in Haskell array update is O(n), right?

That is not a problem for BWT which can use unboxed arrays.

> If that's the case, I suppose that Clean admits a reasonably efficient
> implementation of that algorithm without using too much black magic.

The issue with GHC boxed arrays is an implementation shortcoming in
the GHC garbage collector.  It has nothing to do with the language.
Clean's GC might or might not have the same issue.
0
Reply phr.cx (5483) 7/19/2009 11:37:39 PM

Jon Harrop <jon@ffconsultancy.com> writes:
> I disagree. Haskell is genuinely unpredictable:
> http://www.cs.chalmers.se/~rjmh/Haskell/Messages/Archived.cgi?id=102

A significant theoretical blemish (shared by almost every other
language including C and Java), but it doesn't seem to be a bother in
practice:

http://www.galois.com/blog/2009/04/27/engineering-large-projects-in-haskell-a-decade-of-fp-at-galois/

FWIW, Janis Voigtlaender has done some good work on pinning down
Haskell semantics.
0
Reply phr.cx (5483) 7/20/2009 3:44:34 AM

Alan Mackenzie <acm@muc.de> writes:
> > Read "Purely functional data structures" by Chris Okasaki.
> Hmm.  By some strange coincidence, that book doesn't seem to be on my
> bookshelf.
> 
> Quick excursion via Google.  It seems what Dr. Okasaki is talking about
> in his texts is not data structures which, in some sense, are purely
> functional - it's about using bog standard data structures in languages
> (such as as ML and Haskell) which are functional, to whatever degree of
> purity. 

He is talking about what are sometimes called "persistent data
structures" (google that).  It means structures that efficiently
support operations like "update" without mutation, i.e. by creating a
new structure that shares most of its content with the old.

The book is very good, and a lot of the stuff in it is in the author's
PhD thesis, which might be a good place to get started:

  http://www-2.cs.cmu.edu/~rwh/theses/okasaki.pdf

Related, here is a good article about the benefits of ditching a
mutable structure for a functional one in a particular program: "An
Applicative Control-Flow Graph Based on Huet's Zipper" by Norman
Ramsey and Joao Dias,

  http://www.cs.tufts.edu/~nr/pubs/zipcfg-abstract.html .
0
Reply phr.cx (5483) 7/20/2009 4:08:42 AM

Nobody wrote:
> On Sun, 19 Jul 2009 03:19:16 +0100, Jon Harrop wrote:
>> Java, C#, VB and F# have sufficient support for all of those features
>> that they can be used to solve real problems even where they are relied
>> upon (e.g. games).
> 
> Anything with gc takes a hit on the first 3. They may be good enough for
> some purposes, but they aren't for others.

Yes.

> If you need hard real-time with sub-millisecond latency, malloc/free is
> out, as is accessing any code or data which isn't mlock()d. Obviously
> Haskell doesn't cut it on that front, but nor do the other languages which
> you cite.

Except Java, which does have implementations suitable for hard real time.

> As for how it compares to other languages, worst-case latency is largely a
> question of how aggressive the gc is. And Haskell's memory consumption
> isn't truly unpredictable, it just tends to throw some surprises if you
> aren't paying attention. But that's true (albeit to a lesser extent) of
> most languages which use gc.

I disagree. Haskell is genuinely unpredictable:

http://www.cs.chalmers.se/~rjmh/Haskell/Messages/Archived.cgi?id=102

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/20/2009 4:30:37 AM

On Jul 19, 11:44 pm, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> Jon Harrop <j...@ffconsultancy.com> writes:
> > I disagree. Haskell is genuinely unpredictable:
> >http://www.cs.chalmers.se/~rjmh/Haskell/Messages/Archived.cgi?id=102
>
> A significant theoretical blemish (shared by almost every other
> language including C and Java), but it doesn't seem to be a bother in
> practice:

We are talking about undefined evaluation order correct? If so,
it is important to keep in mind three important points: 1) Java
evaluation order is defined for operands that have side effects
2) C and C++ have implicit sequence points that introduce order
when present  3) C, C++, and Java all have both expressions and
*statements* as central constructs and statements are of course
explicit sequence points. So order of evaluation is far less of
a practical issue in those languages; and, if any code requires
additional explicit sequencing it's introduced quite naturally.

KHD
0
Reply duggar (292) 7/20/2009 4:31:54 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> Can you give us the code? I am particularly interested in your purely
> functional tree implementation in C.

The code is mundane and I would have used email but at least one other
person asked for it so it is attached at the end of this message.  The
following puts the code in some context :-

Claim I:

  Compared to a hash table, a well-implemented purely functional tree
  data structure will perform competitively.  You should not approach
  trees with the assumption that your code will pay a performance
  penalty.

    Real World Haskell page 289.

Some questions :-

Q1. What does "well-implemented" mean?

Q2. What does "purely functional" mean?

Q3. What does "perform competitively" mean?  Does it mean memory, time
    or both?  Does it mean best case, average case, worst case?
    Average of all three?  What does "competitively" mean?  Within a
    order of magnitude?  Within a factor of 2?  Within a factor of
    1.1?

Q4. Is the claim meant to be true for all values of n?

I think a strong hint at the answer to Q1 is the following which
precedes Claim I on page 289 :-

  Implementing a naive tree type is particularly easy in Haskell.
  Beyond that, more useful tree types are also unusually easy to
  implement.  Self-balancing structures, such as red-black trees, have
  struck fear into generations of undergraduate computer science
  students, because the balancing algorithms are notoriously hard to
  get right.

  ...

  Haskell's standard libraries provide two collection types that are
  implemented using balanced trees behind the scenes.

Thus a reasonable interpretation of "well-implemented" is a balanced
tree, such as a red-black tree.  A basic binary tree would not be
considered "well-implemented".  Whether a splay tree with its O(log n)
amortized time counts as "well-implemented" is not so clear.  I'm
going to stick to considering trees don't need th "amortized"
qualifier.

Regarding Q2, given the context of the claim is a book on Haskell then
a likely interpretation of "purely functional" is "persistent".
However, that's not the only possible interpretation.  If one is
programming in a functional language with linear/unique types
(cf. Clean) then the compiler can (though may not :-<) make use of
linearity/uniqueness to perform update in place even though the
algorithm is written in a persistent manner.  The result is much less
memory allocation.

There is no hint for Q3 but for the sake of argument we'll concentrate
on time.  There is no hint as to best, average, or worst case
performance so we'll look at best and worst.  There is no hint on
"competitively" so we'll have to assume there is some factor F and
then try to agree if F is small enough to qualify as "competitively".

There is no hint for Q4 so we either have :-

Strong Claim I

  forall n in Z . perf(hash(n)) <= perf(tree(n))*F

Weak Claim I

  exists (x,y) in (ZxZ) . forall n in {x..y} . perf(hash(n)) <= perf(tree(n))*F

Obviously if F is large enough the strong claim is true.  However, it
is then a meaningless claim.  Similarly if we go with the weak claim
and find that the set {x..y} only has a few elements then that is also
a meaningless claim.  Thus we want the cardinality of {x..y} to be
such that the weak claim applies to practical applications.
Unfortunately that pushes the the issue to a definition of "practical
applications".  Page 289 uses an example of 10,000 nodes in an example
about sharing and whether this was meant to be size used in a
"practical application" or not it would somewhat confusing to use that
example if it was not.  So let's assume the weak claim fails unless
it is true for at least {1..10000} and preferably an even larger
range.

This brings us to :-

Claim II

  The *only* way you can justify [Claim I] is by crippling your hash
  table implementation.

    comp.lang.functional <0YmdnZJlLuvOb8bXnZ2dnUVZ8lidnZ2d@brightview.co.uk>

I'm going to assume this refers to the weak claim rather than the
strong claim.  If that's not the case then there is no need to go any
further.

To test weak claim I and hence II I tested :-

  ht   - fixed size hash table using a linked list to handle collision,

  prb  - a monomorphic persistent red black tree using reference
         counting for memory management.

  pavl - a monomorphic persistent AVL tree using reference counting
         for memory management.

  rb   - a (polymorphic) red black tree (rb) with no reference counting.
         This is an approximation of what a good compiler for a
         language with linear/unique typing _may_ be able to generate.
         
In all cases I used C to avoid any effect GC may have on the results.
I also avoided using malloc(3) so that its quality of implementation
could not affect the results.

I've omitted the re-sizing hash table because :-

a) most of the hash table test are done with the fixed size hash table
   having exactly the same number of buckets as data points (thus if
   the hash is perfect there would be only one value in each bucket)
   and so the resizing version actually performs slightly worse due to
   the extra work done when the table is re-sized.

b) I want to avoid any possible complaint that re-sizing is the cause
   of any performance issues with the hash table.

For reference the tests were done on a Lenovo T60 :-

  $ cat /proc/cpuinfo | egrep "model name|MHz"
  cat /proc/cpuinfo | egrep "model name|MHz"
  model name	: Intel(R) Core(TM)2 CPU         T5500  @ 1.66GHz
  cpu MHz		: 1000.000
  model name	: Intel(R) Core(TM)2 CPU         T5500  @ 1.66GHz
  cpu MHz		: 1000.000

  $ cat /proc/meminfo | grep MemTotal
  cat /proc/meminfo | grep MemTotal
  MemTotal:        1017404 kB
  $ cc -v 2>&1 | tail -1
  gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4) 

  $ cc -O3 john.c -o john
  $ ./john > r

I've put john.c at the the end of the message since it is quite long
and its relevance is only that it will allow a third party to attempt
to reproduce the results I obtained, the important part is the results
themselves.  But before we look at any results I'd like to ask anyone
who believes in imperative languages which have "predictable
performance" to state what a graph of the results will look for for
values of n varying from 100 to 10,0000,0000?  Will the hash table
results be linear in n, polynomial in n, exponential in n?  Same
question for the tree results?  Note I'm not asking for a linear
constant or the polynomial degree just whether the results will fall
into one of three very broad categories.  If you can predict a
constant or degree all the better.

So, keeping your predictions in mind, here are the results I get :-

  $ cat r
  ht	       100        100 0.16
  rb	       100          0 0.23
  prb	       100          0 0.58
  pavl	       100          0 0.63
  ht	       250        250 0.24
  rb	       250          0 0.39
  prb	       250          0 0.143
  pavl	       250          0 0.158
  ht	       500        500 0.36
  rb	       500          0 0.71
  prb	       500          0 0.304
  pavl	       500          0 0.339
  ht	       750        750 0.52
  rb	       750          0 0.106
  prb	       750          0 0.485
  pavl	       750          0 0.540
  ht	      1000       1000 0.66
  rb	      1000          0 0.142
  prb	      1000          0 0.633
  pavl	      1000          0 0.747
  ht	      1000        100 0.81
  ht	      1000         10 0.188
  ht	      1000          1 0.1281
  ht	      2500       2500 0.158
  rb	      2500          0 0.374
  prb	      2500          0 0.1820
  pavl	      2500          0 0.2135
  ht	      5000       5000 0.314
  rb	      5000          0 0.817
  prb	      5000          0 0.3918
  pavl	      5000          0 0.4659
  ht	      7500       7500 0.474
  rb	      7500          0 0.1318
  prb	      7500          0 0.6254
  pavl	      7500          0 0.7344
  ht	     10000      10000 0.634
  rb	     10000          0 0.1827
  prb	     10000          0 0.8720
  pavl	     10000          0 0.10372
  ht	     10000       1000 0.1003
  ht	     10000        100 0.4892
  ht	     10000         10 0.42870
  ht	     25000      25000 0.1606
  rb	     25000          0 0.5273
  prb	     25000          0 0.26102
  pavl	     25000          0 0.29457
  ht	     50000      50000 0.3347
  rb	     50000          0 0.11625
  prb	     50000          0 0.55170
  pavl	     50000          0 0.64388
  ht	     75000      75000 0.5174
  rb	     75000          0 0.18590
  prb	     75000          0 0.86948
  pavl	     75000          0 0.102214
  ht	    100000     100000 0.7993
  rb	    100000          0 0.26667
  prb	    100000          0 0.123833
  pavl	    100000          0 0.142501
  ht	    100000      10000 0.12723
  ht	    100000       1000 0.71383
  ht	    100000        100 0.630548
  ht	    250000     250000 0.34738
  rb	    250000          0 0.108903
  prb	    250000          0 0.431491
  pavl	    250000          0 0.476282
  ht	    500000     500000 0.87062
  rb	    500000          0 0.319648
  prb	    500000          0 1.162610
  pavl	    500000          0 1.256194
  ht	    750000     750000 0.135599
  rb	    750000          0 0.576284
  prb	    750000          0 2.17145
  pavl	    750000          0 2.114378
  ht	   1000000    1000000 0.186973
  rb	   1000000          0 0.854929
  prb	   1000000          0 2.964288
  pavl	   1000000          0 3.75486
  ht	   1000000     100000 0.510172
  ht	   1000000      10000 4.988925
  ht	   1000000       1000 50.173156
  ht	   2500000    2500000 0.500639
  rb	   2500000          0 2.804329
  prb	   2500000          0 9.243149
  pavl	   2500000          0 9.639243
  ht	   5000000    5000000 1.24295
  rb	   5000000          0 6.887620
  prb	   5000000          0 21.45345
  pavl	   5000000          0 22.77399
  ht	   7500000    7500000 1.570430
  rb	   7500000          0 10.801139
  prb	   7500000          0 33.974976
  pavl	   7500000          0 35.311648
  ht	  10000000   10000000 2.129251
  rb	  10000000          0 15.223801
  prb	  10000000          0 47.628965
  pavl	  10000000          0 49.485987
  ht	  10000000    1000000 6.225125
  ht	  10000000     100000 60.995422
  ht	  10000000      10000 599.944561

The third column is only relevant for ht and there it indicates the
size of the hash table.  The fourth column is the time in seconds to
insert n integers where n is the value in the second column.  While
the numbers are great for precise detail, it is hard to easily
identify see patterns so let's plot some graphs :-

  $ cat r2p
  #!/bin/sh

  limit=${2:-10000000}

  for t in ht rb prb pavl
  do
          awk -v t=$t -v l=$limit '($1 == t) && ($1 != "ht" || $2 == $3) && ($2 <= l) { printf("%s %s\n", $2, $4); }' $1 > $t
  done 

  for n in 10 100 1000
  do
          awk -v n=$n -v l=$limit '($1 == "ht" && ($2 == n*$3) && ($2 <= l)) { printf("%s %s\n", $2, $4); }' $1 > ht.$n
  done
  $ ./r2p r
  $ cat plot.all
  set terminal dumb
  set logscale x
  set logscale y
  set key left
  plot 'ht'
  replot 'prb'
  replot 'pavl'
  replot 'rb'
  replot 'ht.10'
  replot 'ht.100'
  replot 'ht.1000'
  $ gnuplot plot.all

    1000 ++--+-----+-+-+---+----+--++---+-----+-+-+---+----+--++---+-----+--++
         +     'ht'   A+            +             +            +             G
         +    'prb'   B                                                      +
         +   'pavl'   C                                                      +
         |     'rb'   D                                                      |
     100 ++ 'ht.10'   E                                                     ++
         + 'ht.100'   F                                        G             F
         +'ht.1000'   G                                                    B B
         +                                                               B   +
         |                                                                   D
      10 ++                                                          B     D++
         +                                                               D   E
         +                                                     C             +
         +                                                    BB     D       A
         |                                                                 A |
       1 ++            E        D   B           B A        A   D         A  ++
         B         D A A           BA     D   B A F           DE             +
         +    D    A B      D   B  AF         A        A   D         A       +
         D    A    B        C   A         B       D                          +
         A    B        D    A      DD     A     D C           AA             +
     0.1 ++--+-----+-D-+---+----+--+C---+-----D-C-B---+D---+--++---+-----+--++
        100           1000        10000         100000       1e+06        1e+07

The plot is somewhat cluttered but some general trends are that :-

1. for n <= 100,000 all the times at this scale are around the same
   order of magnitude and there is a sawtooth pattern to the results
   for all algorithms.  I bow down to anyone who predicated a sawtooth
   pattern and can explain why it occurs.  It is not hard to suggest
   some possible reasons for the sawtooth but I haven't used any tools to
   confirm/deny any possibilities.

2. for n >= 100,000 and more obviously n >= 1,000,000 the results
   favour a hash table that has sufficient buckets to avoid the effect
   of collisions coming in to effect (A) with the trees being at least
   an order of magnitude worse.

3. If you can make out E, F and G amid all those points you'll see
   that the performance of the hash table when collisions dominate can
   be an order of magnitude or more worse than a tree.

There is not much more to say about point 2.  Unless we are generous
with F then it is clear that {x..y} is at best {1..100000} if we
ignore collisions.

So, let's look at point 1 in some more detail.  If we look at n <=
100,000 in isolation and ignore the ht.X variants :-

  $ ./r2p r 100000
  $ cat plot.low
  set terminal dumb
  set logscale x
  set key left
  plot 'ht'
  replot 'prb'
  replot 'pavl'
  replot 'rb'
  $ gnuplot plot.low

    0.9 ++-----+---+--+-+-++-+++------+---+--+-+-++-+++------+---+--+-+-++-+++
        +  'ht'   A            +                      B                   B  +
        | 'prb'   B                            D                             |
    0.8 +'pavl'   C                                                         +A
        |  'rb'   D            C                   C                         |
    0.7 ++              D                                                   ++
        |                      A                                      C      |
        C                      B                   B  A                      |
    0.6 B+                                                                  ++
        |                   A                                  D      B      |
    0.5 ++                  B                                             A ++
        |                                      C   A                         |
    0.4 ++                                                                  ++
        |        D                      D      B                             |
        |               A                                             A      |
    0.3 ++              B                      A               C            ++
        |                                                      B             D
    0.2 D+       A                      C                                   ++
        |                               B             D        A          D  |
        A        B             D        A          D  +                      B
    0.1 ++-----+---+--+-+-++D+++------+---+--+-+-++-++C------+---+--+-D-++C+++
       100                    1000                  10000                100000

Now the sawtooth pattern is more obvious.  The fact the sawtooth for each
algorithm is different means that no implementation is consistently
faster than all the others.  Instead you either have to pick a set of
values of interest or take an average over all values to try and pick
the fastest.  

For F = 10 the weak claim is true in the range {1..100000}.  I'm using
F = 10 here because while the hash table is is up to 5x faster than
the trees for some values of n, the hash table is also up to 6x slower
than the trees for some values of n.

If we reduce the clutter and concentrate specifically on hash table
and persistent red black tree for n <= 100,000 :-

  $ cat plot.low.ht.prb
  set terminal dumb
  set logscale x
  set logscale y
  set key left
  plot 'ht'
  replot 'prb'
  $ gnuplot plot.low.ht.prb

      1 ++-----+---+--+-+-++-+++------+---+--+-+-++-+++------+---+--+-+-++-+++
        + 'ht'   A             +                      B                   B  +
        +'prb'   B                                                           A
        +                                                                    +
        +                      A                   B  A                      +
        B                                                             B      |
        +                   A                      A                      A  +
        |                                                                    |
        +                                      B                             +
        |               A                                                    |
        +               B                      A                      A      +
        |                                                                    |
        |        A                                             B             |
        |                                                                    |
        +                                                                    +
        |                               B                                    |
        A                               A                      A             |
        |        B                                                           |
        |                                                                    B
        +                      +                      +                      +
    0.1 ++-----+---+--+-+-++-+++------+---+--+-+-++-+++------+---+--+-+-++-+++
       100                    1000                  10000                100000

If we ignore n = 100 (bad for tree) and n = 100000 (bad for hash) then
for many of the other points we can use a value of F ~= 2 and meet the
weak claim.  Note for n = 750 and n = 1000 the results are very close
(persistent red-black tree is marginally quicker in both cases) but
gnuplot can only plot one character in "dumb" mode and the hash table
value is shown.

To show that there is nothing special about a persistent red-black
tree, here's the comparison of a hash table with a persistent AVL tree :-

  $ cat plot.low.ht.pavl
  set terminal dumb
  set logscale x
  set logscale y
  set key left
  plot 'ht'
  replot 'pavl'
  $ gnuplot plot.low.ht.pavl

      1 ++-----+---+--+-+-++-+++------+---+--+-+-++-+++------+---+--+-+-++-+++
        +  'ht'   A            +                      +                      +
        +'pavl'   B                                                          A
        +                      B                   B                         +
        B                      A                      A               B      +
        |                   B                                                |
        +                   A                      A                      A  +
        |                                      B                             |
        +                                                                    +
        |               A                                                    |
        +                                      A                      A      +
        |                                                      B             |
        |        A                                                           |
        |                               B                                    |
        +                                                                    +
        |                                                                    |
        A        B                      A                      A             |
        |                                                                    B
        |                                                                    |
        +                      +                      +                      +
    0.1 ++-----+---+--+-+-++-+++------+---+--+-+-++-++B------+---+--+-+-++B+++
       100                    1000                  10000                100000

The results are similar though here the sawtooth overlaps are more
advantageous for the AVL than they were for the red black tree such
that there are four values (250, 1000, 75,000, 100,000) where the AVL
tree is more than 2x faster and up to 5x faster than the hash table
wereas the hash table is rarely 2x faster than the AVL.

Finally comparing the hash table with a non-persistent red-black tree :-

  $ cat plot.low.ht.rb
  set terminal dumb
  set logscale x
  set logscale y
  set key left
  plot 'ht'
  replot 'rb'
  $ gnuplot plot.low.ht.rb

      1 ++-----+---+--+-+-++-+++------+---+--+-+-++-+++------+---+--+-+-++-+++
        +'ht'   A              +                      +                      +
        +'rb'   B                              B                             A
        +               B                                                    +
        +                      A                      A                      +
        |                                                                    |
        +                   A                      A           B          A  +
        |                                                                    |
        +        B                                                           +
        |               A               B                                    |
        +                                      A                      A      +
        |                                                                    B
        |        A                                                           |
        B                                                                    |
        +                                                                    +
        |                                             B                   B  |
        A                               A                      A             |
        |                      B                                             |
        |                                          B                         |
        +                   B  +                      +               B      +
    0.1 ++-----+---+--+-+-++-+++------+---+--+-+-++-+++------+---+--+-+-++-+++
       100                    1000                  10000                100000

Again the sawtooth pattern comes through clearly and there is no clear
winner across the whole range.

Looking now at point 3 I'm only going to use the non-persistent
red-black tree for comparision since I want to compare worst case
behaviour.  This is a practical concern when choosing an algorithm and
in practice one would not be comparing persistent X and non-persistent Y.

  $ cat plot.high.ht.rb
  set terminal dumb
  set logscale x
  set logscale y
  set key left
  plot 'rb.high'
  replot 'ht.100'
  replot 'ht.1000'

where rb.high just restricts rb to those values of x that are in ht.X :-

  $ cat rb.high
  1000 0.142
  10000 0.1827
  100000 0.26667
  1000000 0.854929
  10000000 15.223801
  $ gnuplot plot.high.ht.rb

    1000 ++--+-----+-+-+---+----+--++---+-----+-+-+---+----+--++---+-----+--++
         +'rb.high'   A+            +             +            +             C
         + 'ht.100'   B                                                      +
         +'ht.1000'   C                                                      +
         |                                                                   |
     100 ++                                                                 ++
         +                                                     C             B
         +                                                                   +
         +                                                                   +
         |                                                                   A
      10 ++                                                                 ++
         +                                                                   +
         +                                                     B             +
         +                                                                   +
         |                                                                   |
       1 ++                                                    A            ++
         +                                        B                          +
         +                          B                                        +
         +                                        A                          +
         +             A            A             +            +             +
     0.1 ++--+-----+-+-+---+----+--++---+-----+-+-+---+----+--++---+-----+--++
        100           1000        10000         100000       1e+06        1e+07

Notice that the red-black tree is consistently better and and as
n > 1,000,000 the red-black tree is 10-100x better due to the massive
number of collisions causing long lists and so poor insert times.

As has been discussed earlier in this thread the poor hash table
performance can be fixed by either resizing the hash table or using
something other than a linked list to deal with collisions.  If one
chooses a balanced tree then the worst case performance is that of a
balanced tree which makes the weak claim is true for worst case
performance.

In the context I'm interested in (kernel) re-sizing a 10,000,000 entry
hash table is not really an option because it assumes :-

a) one can at any time allocate a 40MB chunk of physically
   contiguous memory to hold the new buckets.  Such an allocation is
   unlikely to succeed.

b) in the unlikely event one has the memory, one can afford to take a
   write lock lock on the table for the time it takes to rehash
   (anywhere from 0.1 - 2 seconds depending on the size of the table).

Thus kernels often to use fixed size hash tables and :-

a) limit the number of elements to avoid the above behaviour thus
   requiring re-compilation if you actually need a bigger limit.
   Somewhat problematic if ou are trying to sell a single product to
   multiple customers.

b) allocate the maximum number of buckets statically -- somewhat
   problematic when you have multiple tables (session table, route
   cache, ARP table, bridge table, IPsec SA map) and different
   cusomers want to maximize the size of different tables.

c) use some kind of keyed hash to thwart attackers from causing a
   problem even when the number of nodes is << the number of buckets.

d) do nothing and exhibit dramatic performance problems.

Finally here's the code :-

  $ cat john.c
  #include <stdlib.h>
  #include <stdio.h>
  #include <time.h>
  #include <math.h>


  /*
   * Maximum number of values that will be used in any test.
   * It is declared so that we can statically allocate memory
   * for the various node types that will be used and thus
   * avoid memory allocation affecting the performance.
   */

  enum {
          N = 10*1000*1000
  };

  /*
   * The keys are stored in an array so that we can use the same
   * values for testing all data structures.
   */
  static int keys[N];



  /*
   * Generic container as used in Linux kernel though this is not
   * the version that is used in 2.6, it probably comes from 2.4.
   */

  #define container_of(ptr, type, member) \
          ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))


  /*
   * List taken from Linux kernel include/linux/list.h
   */

  #define list_entry(ptr, type, member) \
          container_of(ptr, type, member)

  struct list_head {
          struct list_head *next, *prev;
  };

  static inline void INIT_LIST_HEAD(struct list_head *list)
  {
          list->next = list;
          list->prev = list;
  }

  #define list_for_each(pos, head) \
          for (pos = (head)->next; pos->next, pos != (head); \
                  pos = pos->next)


  static inline void __list_add(struct list_head *new,
                                struct list_head *prev,
                                struct list_head *next)
  {
          next->prev = new;
          new->next = next;
          new->prev = prev;
          prev->next = new;
  }


  static inline void list_add(struct list_head *new, struct list_head *head)
  {
          __list_add(new, head, head->next);
  }


  /*
   * Red Black Tree taken from Linux kernel 2.6 include/linux/rbtree.h
   * This code is under GPL
   */

  struct rb_node
  {
          unsigned long  rb_parent_color;
  #define	RB_RED		0
  #define	RB_BLACK	1
          struct rb_node *rb_right;
          struct rb_node *rb_left;
  };

  struct rb_root
  {
          struct rb_node *rb_node;
  };

  #define rb_parent(r)   ((struct rb_node *)((r)->rb_parent_color & ~3))
  #define rb_color(r)   ((r)->rb_parent_color & 1)
  #define rb_is_red(r)   (!rb_color(r))
  #define rb_is_black(r) rb_color(r)
  #define rb_set_red(r)  do { (r)->rb_parent_color &= ~1; } while (0)
  #define rb_set_black(r)  do { (r)->rb_parent_color |= 1; } while (0)

  static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
  {
          rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
  }

  static inline void rb_set_color(struct rb_node *rb, int color)
  {
          rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
  }

  #define	rb_entry(ptr, type, member) container_of(ptr, type, member)

  static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
                                  struct rb_node ** rb_link)
  {
          node->rb_parent_color = (unsigned long )parent;
          node->rb_left = node->rb_right = 0;
          *rb_link = node;
  }

  /*
   * Red Black insert tree taken from Linux kernel 2.6 lib/rbtree.c
   * This code is also under GPL.
   */

  static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
  {
          struct rb_node *right = node->rb_right;
          struct rb_node *parent = rb_parent(node);

          if ((node->rb_right = right->rb_left))
                  rb_set_parent(right->rb_left, node);
          right->rb_left = node;

          rb_set_parent(right, parent);

          if (parent)
          {
                  if (node == parent->rb_left)
                          parent->rb_left = right;
                  else
                          parent->rb_right = right;
          }
          else
                  root->rb_node = right;
          rb_set_parent(node, right);
  }


  static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
  {
          struct rb_node *left = node->rb_left;
          struct rb_node *parent = rb_parent(node);

          if ((node->rb_left = left->rb_right))
                  rb_set_parent(left->rb_right, node);
          left->rb_right = node;

          rb_set_parent(left, parent);

          if (parent)
          {
                  if (node == parent->rb_right)
                          parent->rb_right = left;
                  else
                          parent->rb_left = left;
          }
          else
                  root->rb_node = left;
          rb_set_parent(node, left);
  }


  static void rb_insert_color(struct rb_node *node, struct rb_root *root)
  {
          struct rb_node *parent, *gparent;

          while ((parent = rb_parent(node)) && rb_is_red(parent))
          {
                  gparent = rb_parent(parent);

                  if (parent == gparent->rb_left)
                  {
                          {
                                  register struct rb_node *uncle;

                                  uncle = gparent->rb_right;
                                  if (uncle && rb_is_red(uncle))
                                  {
                                          rb_set_black(uncle);
                                          rb_set_black(parent);
                                          rb_set_red(gparent);
                                          node = gparent;
                                          continue;
                                  }
                          }

                          if (parent->rb_right == node)
                          {
                                  register struct rb_node *tmp;
                                  __rb_rotate_left(parent, root);
                                  tmp = parent;
                                  parent = node;
                                  node = tmp;
                          }

                          rb_set_black(parent);
                          rb_set_red(gparent);
                          __rb_rotate_right(gparent, root);
                  } else {
                          {
                                  register struct rb_node *uncle;

                                  uncle = gparent->rb_left;
                                  if (uncle && rb_is_red(uncle))
                                  {
                                          rb_set_black(uncle);
                                          rb_set_black(parent);
                                          rb_set_red(gparent);
                                          node = gparent;
                                          continue;
                                  }
                          }

                          if (parent->rb_left == node)
                          {
                                  register struct rb_node *tmp;
                                  __rb_rotate_right(parent, root);
                                  tmp = parent;
                                  parent = node;
                                  node = tmp;
                          }

                          rb_set_black(parent);
                          rb_set_red(gparent);
                          __rb_rotate_left(gparent, root);
                  }
          }

          rb_set_black(root->rb_node);
  }


  /*
   * monomorphic non-persistent Red Black Tree
   */

  struct rb_d_node {
          int n;
          union {
                  struct rb_node rb_node;
                  struct rb_d_node *free;
          };
  };

  static struct rb_d_node *rb_d_nodes_free_list;
  static struct rb_root rb_d_root;


  static struct rb_d_node *rb_d_node_new(void)
  {
          struct rb_d_node *t;

          t = rb_d_nodes_free_list;
          rb_d_nodes_free_list = rb_d_nodes_free_list->free;
          return t;
  }


  static void rb_d_node_free(struct rb_d_node *n)
  {
          n->free = rb_d_nodes_free_list;
          rb_d_nodes_free_list = n;
  }


  static void rb_d_tree_insert(int d)
  {
          struct rb_d_node *n, *o;
          struct rb_root *root = &rb_d_root;
          struct rb_node **p = &rb_d_root.rb_node;
          struct rb_node *parent = 0;

          n = rb_d_node_new();
          if (!n)
                  return;
          n->n = d;
          while (*p) {
                  parent = *p;
                  o = rb_entry(parent, struct rb_d_node, rb_node);

                  if (d < o->n) {
                          p = &(*p)->rb_left;
                  } else if (d > o->n) {
                          p = &(*p)->rb_right;
                  } else {
                          /* dup */
                          rb_d_node_free(n);
                          return;
                  }
          }
          rb_link_node(&n->rb_node, parent, p);
          rb_insert_color(&n->rb_node, root);
  }


  static int rb_d_tree_find(int d)
  {
          struct rb_node *p = rb_d_root.rb_node;
          struct rb_d_node *n;

          while (p) {
                  n = rb_entry(p, struct rb_d_node, rb_node);

                  if (d < n->n)
                          p = p->rb_left;
                  else if (d > n->n)
                          p = p->rb_right;
                  else 
                          return 1;
          }
          return 0;
  }



  static void rb_d_tree_insert_test(unsigned int n)
  {
          unsigned int i;
          int dup;

          for (i = 0; i != n; i += 1)
                  rb_d_tree_insert(keys[i]);
  }


  static void rb_d_tree_find_test(unsigned int n)
  {
          unsigned int i;
          int found;

          for (i = 0; i != n; i += 1) {
                  if (!rb_d_tree_find(keys[i]))
                          printf("rb tree lookup %d failed\n", keys[i]);
          }
  }


  /*
   * monomorphic non-persistent fixed size hash table
   */

  struct hash_node {
          int n;
          unsigned int hash;
          union {
                  struct list_head hash_link;
                  struct hash_node *free;
          };
  };

  static struct list_head hash_table[N];
  static struct hash_node *hash_nodes_free;


  /*
   * Hopefully a faithful implementation of the hash function for ints
   * that O'Caml 3.10 uses, see ocaml-3.11.0/byterun/hash.c:hash_aux.c.
   */
  static inline unsigned int ocaml_hash_int(int d)
  {
          unsigned int hash_accu = 0;
          unsigned int i;

          hash_accu = hash_accu*65599 + d;
          return hash_accu;
  }


  static void init_hash_table(void)
  {
          int i;

          for (i = 0; i != N; i += 1)
                  INIT_LIST_HEAD(&hash_table[i]);
  }


  static inline struct hash_node *hash_node_new(void)
  {
          struct hash_node *t;

          t = hash_nodes_free;
          hash_nodes_free = hash_nodes_free->free;
          return t;
  }


  static void hash_insert(unsigned int max, int d) 
  {
          unsigned int h;
          unsigned int b;
          struct list_head *head, *l;
          struct hash_node *hn;

          h = ocaml_hash_int(d);
          b = h%max;
          list_for_each(l, &hash_table[b]) {
                  hn = list_entry(l, struct hash_node, hash_link);
                  if (h != hn->hash)
                          continue;
                  if (d == hn->n)
                          return;
          }
          hn = hash_node_new();
          if (!hn)
                  return;
          hn->n = d;
          hn->hash = h;
          list_add(&hn->hash_link, &hash_table[b]);
  }


  static int hash_find(unsigned int max, int d)
  {
          unsigned int b;
          unsigned int h;
          struct hash_node *hn;
          struct list_head *head, *l;

          h = ocaml_hash_int(d);
          b = h%max;
          head = &hash_table[b];
          list_for_each(l, head) {
                  hn = list_entry(l, struct hash_node, hash_link);
                  if (h != hn->hash)
                          continue;
                  if (d == hn->n)
                          return 1;
          }
          return 0;
  }


  static void hash_insert_test(unsigned int n, unsigned int max)
  {
          unsigned int i;

          for (i = 0; i != n; i += 1)
                  hash_insert(max, keys[i]);
  }


  static void hash_find_test(unsigned int n, unsigned int max)
  {
          unsigned int i;
          unsigned int b;
          unsigned int h;
          struct node *e;
          struct list_head *head, *l;
          int found;

          for (i = 0; i != n; i += 1) {
                  if (!hash_find(max, keys[i]))
                          printf("hash find %d failed\n", keys[i]);
          }
  }



  /*
   * Monomorphic Persistent Red Black Tree.
   * Reference counts are used to support persistence.
   * The code is based on a purely functional exposition of Red-Black trees
   * in Scheme or Haskell, I forget which.  Since I wrote the C code 
   * then should anyone actually want to use it for something there
   * is not need to ask, you can use it under the BSD/Berkeley license
   * http://www.openbsd.org/policy.html.  Supporting deletion is left
   * as an excercise for the reader :-)
   */

  enum {
          BLACK = 0,
          RED = 1
  };

  struct prbt {
          struct prbt *l, *r;
          unsigned short u;
          unsigned short c;
          int d;
  };


  static struct prbt *prbt_free_list;


  static inline struct prbt *prbt_new(void)
  {
          struct prbt *t;

          t = prbt_free_list;
          prbt_free_list = prbt_free_list->l;
          return t;
  }


  static inline struct prbt *prbt_get(struct prbt *n)
  {
          if (n)
                  n->u += 1;
          return n;
  }

  /*
   * The noinline is to stop gcc diverging as it tries to recursively
   * inline prtt_free and prbt_put.
   */
  static void prbt_free(struct prbt *) __attribute__((noinline));;

  /*
   * prbt_put is small enough and called frequently enough that if
   * the code was being generated by a compiler for a language that uses
   * reference counts then it should inline it.  That said, the only non-trivial
   * functional language that I'm aware of that uses reference counts
   * is Opal (http://user.cs.tu-berlin.de/~opal/) and I've never investigated
   * whether it does or not.  The inlining can be removed and it doesn't
   * make a significant difference to the results.
   */

  static void prbt_put(struct prbt *) __attribute__((always_inline));


  static void prbt_put(struct prbt *n)
  {
          if (!n)
                  return;
          n->u -= 1;
          if (n->u)
                  return;
          prbt_free(n);
  }


  static void prbt_free(struct prbt *n)
  {
          if (n->l)
                  prbt_put(n->l);
          if (n->r)
                  prbt_put(n->r);
          n->l = prbt_free_list;
          prbt_free_list = n;
  }


  struct prbt *prbt_bal(struct prbt *l, int d, struct prbt *r)
  {
          struct prbt *nl, *nr, *p, *ll, *lr, *rr, *rl;

          if (l && (l->c == RED)) {
                  ll = l->l;
                  lr = l->r;
                  if (r && (r->c == RED)) {
                          nl = prbt_new();
                          if (!nl)
                                  return 0;
                          nr = prbt_new();
                          if (!nr) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  return 0;
                          }
                          p = prbt_new();
                          if (!p) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  nr->u = 1;
                                  nr->l = 0;
                                  nr->r = 0;
                                  prbt_put(nr);
                                  return 0;
                          }
                          nl->l = prbt_get(ll);
                          nl->r = prbt_get(lr);
                          nl->c = BLACK;
                          nl->u = 1;
                          nl->d = l->d;
                          nr->l = prbt_get(r->l);
                          nr->r = prbt_get(r->r);
                          nr->c = BLACK;
                          nr->u = 1;
                          nr->d = r->d;
                          p->l = nl;
                          p->r = nr;
                          p->c = RED;
                          p->d = d;
                          p->u = 1;
                          return p;
                  }
                  if (ll && (ll->c == RED)) {
                          nl = prbt_new();
                          if (!nl)
                                  return 0;
                          nr = prbt_new();
                          if (!nr) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  return 0;
                          }
                          p = prbt_new();
                          if (!p) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  nr->u = 1;
                                  nr->l = 0;
                                  nr->r = 0;
                                  prbt_put(nr);
                                  return 0;
                          }
                          nl->l = prbt_get(ll->l); /*  */
                          nl->r = prbt_get(ll->r);
                          nl->c = BLACK;
                          nl->u = 1;
                          nl->d = ll->d;
                          nr->l = prbt_get(lr);
                          nr->r = prbt_get(r);
                          nr->c = BLACK;
                          nr->u = 1;
                          nr->d = d;
                          p->l = nl;
                          p->r = nr;
                          p->c = RED;
                          p->d = l->d;
                          p->u = 1;
                          return p;
                  }
                  if (lr && (lr->c == RED)) {
                          nl = prbt_new();
                          if (!nl)
                                  return 0;
                          nr = prbt_new();
                          if (!nr) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  return 0;
                          }
                          p = prbt_new();
                          if (!p) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  nr->u = 1;
                                  nr->l = 0;
                                  nr->r = 0;
                                  prbt_put(nr);
                                  return 0;
                          }
                          nl->l = prbt_get(ll);
                          nl->r = prbt_get(lr->l);
                          nl->c = BLACK;
                          nl->u = 1;
                          nl->d = l->d;
                          nr->l = prbt_get(lr->r);
                          nr->r = prbt_get(r);
                          nr->c = BLACK;
                          nr->u = 1;
                          nr->d = d;
                          p->l = nl;
                          p->r = nr;
                          p->c = RED;
                          p->d = lr->d;
                          p->u = 1;
                          return p;
                  }
          }
          if (r && (r->c == RED)) {
                  rr = r->r;
                  rl = r->l;
                  if (rr && (rr->c == RED)) {
                          nl = prbt_new();
                          if (!nl)
                                  return 0;
                          nr = prbt_new();
                          if (!nr) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  return 0;
                          }
                          p = prbt_new();
                          if (!p) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  nr->u = 1;
                                  nr->l = 0;
                                  nr->r = 0;
                                  prbt_put(nr);
                                  return 0;
                          }
                          nl->l = prbt_get(l);
                          nl->r = prbt_get(rl);
                          nl->c = BLACK;
                          nl->u = 1;
                          nl->d = d;
                          nr->l = prbt_get(rr->l);
                          nr->r = prbt_get(rr->r);
                          nr->c = BLACK;
                          nr->u = 1;
                          nr->d = rr->d;
                          p->l = nl;
                          p->r = nr;
                          p->c = RED;
                          p->d = r->d;
                          p->u = 1;
                          return p;
                  }
                  if (rl && (rl->c == RED)) {
                          nl = prbt_new();
                          if (!nl)
                                  return 0;
                          nr = prbt_new();
                          if (!nr) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  return 0;
                          }
                          p = prbt_new();
                          if (!p) {
                                  nl->u = 1;
                                  nl->l = 0;
                                  nl->r = 0;
                                  prbt_put(nl);
                                  nr->u = 1;
                                  nr->l = 0;
                                  nr->r = 0;
                                  prbt_put(nr);
                                  return 0;
                          }
                          nl->l = prbt_get(l);
                          nl->r = prbt_get(rl->l);
                          nl->c = BLACK;
                          nl->u = 1;
                          nl->d = d;
                          nr->l = prbt_get(rl->r);
                          nr->r = prbt_get(rr);
                          nr->c = BLACK;
                          nr->u = 1;
                          nr->d = r->d;
                          p->l = nl;
                          p->r = nr;
                          p->c = RED;
                          p->d = rl->d;
                          p->u = 1;
                          return p;
                  }
          }
          p = prbt_new();
          if (!p)
                  return 0;
          p->l = prbt_get(l);
          p->r = prbt_get(r);
          p->c = BLACK;
          p->d = d;
          p->u = 1;
          return p;
  }



  struct prbt *prbt_ins(struct prbt *r, int d)
  {
          struct prbt *n, *t;

          if (!r) {
                  n = prbt_new();
                  if (!n)
                          return 0;
                  n->l = 0;
                  n->r = 0;
                  n->u = 1;
                  n->c = RED;
                  n->d = d;
                  return n;
          }
          switch (r->c) {
          case RED:
                  if (d < r->d) {
                          t = prbt_ins(r->l, d);
                          if (!t)
                                  return 0;
                          n = prbt_new();
                          if (!n) {
                                  prbt_put(t);
                                  return 0;
                          }
                          n->l = t;
                          n->r = prbt_get(r->r);
                          n->c = RED;
                          n->u = 1;
                          n->d = r->d;
                          return n;
                  } else if (d > r->d) {
                          t = prbt_ins(r->r, d);
                          if (!t)
                                  return 0;
                          n = prbt_new();
                          if (!n) {
                                  prbt_put(t);
                                  return 0;
                          }
                          n->l = prbt_get(r->l);
                          n->r = t;
                          n->c = RED;
                          n->u = 1;
                          n->d = r->d;
                          return n;
                  } else {
                          r->u += 1;
                          return r;
                  }
                  break;
          case BLACK:
                  if (d < r->d) {
                          t = prbt_ins(r->l, d);
                          n = prbt_bal(t, r->d, r->r);
                          prbt_put(t);
                          return n;
                  } else if (d > r->d) {
                          t = prbt_ins(r->r, d);
                          n = prbt_bal(r->l, r->d, t);
                          prbt_put(t);
                          return n;
                  } else {
                          r->u += 1;
                          return r;
                  }
                  break;
          }
          return 0;		/* never get here */
  }


  struct prbt *prbt_add(struct prbt *r, int d)
  {
          struct prbt *nr, *n;

          nr = prbt_ins(r, d);
          if (!nr)
                  return nr;
          if (nr->u == 1) {
                  nr->c = BLACK;
                  return nr;
          }
          n = prbt_new();
          if (!n)
                  return 0;
          n->l = prbt_get(nr->l);
          n->r = prbt_get(nr->r);
          n->u = 1;
          n->c = BLACK;
          n->d = nr->d;
          prbt_put(nr);
          return n;
  }


  static struct prbt *prbt_find(struct prbt *r, int d)
  {
          if (!r)
                  return 0;
          if (d < r->d)
                  return prbt_find(r->l, d);
          else if (d > r->d)
                  return prbt_find(r->r, d);
          else 
                  return r;
  }

  static struct prbt *prbt_root;


  static void prbt_insert_test(unsigned int n)
  {
          unsigned int i;
          struct prbt *nr, *or = prbt_root;

          for (i = 0; i != n; i += 1) {
                  nr = prbt_add(or, keys[i]);
                  prbt_put(or);
                  or = nr;
          }
          prbt_root = or;
  }


  static void prbt_find_test(unsigned int n)
  {
          struct prbt *r = prbt_root;
          struct prbt *f;
          unsigned int i;

          for (i = 0; i != n; i += 1) {
                  f = prbt_find(r, keys[i]);
                  if (!f)
                          printf("prb find %d failed\n", keys[i]);
          }
  }


  /*
   * Persistent AVL tree.
   * C code is based on Scheme code I wrote some time ago.
   * http://www.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/scheme/code/ext/avl/
   * As with the Persistent Red Black tree if for any reason you want to
   * use this code then you can under BSD/Berkely license whose terms are
   * available at http://www.openbsd.org/policy.html.
   */

  struct pavl_node {
          struct pavl_node *l, *r;
          int d;
          unsigned int h;
          unsigned int u;
  };



  static struct pavl_node *pavl_free_list;
  static struct pavl_node *pavl_root;


  static struct pavl_node *pavl_node_new(void)
  {
          struct pavl_node *t;

          t = pavl_free_list;
          pavl_free_list = pavl_free_list->l;
          return t;
  }

  static inline struct pavl_node *pavl_node_get(struct pavl_node *n)
  {
          if (n)
                  n->u += 1;
          return n;
  }

  static void pavl_node_free(struct pavl_node *) __attribute__((noinline));;

  static void pavl_node_put(struct pavl_node *) __attribute__((always_inline));

  static void pavl_node_put(struct pavl_node *n)
  {
          if (!n)
                  return;
          n->u -= 1;
          if (n->u)
                  return;
          pavl_node_free(n);
  }


  static void pavl_node_free(struct pavl_node *n)
  {
          if (n->l)
                  pavl_node_put(n->l);
          if (n->r)
                  pavl_node_put(n->r);
          n->l = pavl_free_list;
          pavl_free_list = n;
  }


  struct pavl_node *
  pavl_bal(struct pavl_node *l, int a, 
           struct pavl_node *m, int c, struct pavl_node *r)
  {
          struct pavl_node *nl, *nr, *n;
          unsigned int lh = l ? l->h : 0;
          unsigned int mh = m ? m->h : 0;
          unsigned int rh = r ? r->h : 0;

          if ((mh > lh) && (mh > rh)) {
                  nl = pavl_node_new();
                  if (!nl)
                          return 0;
                  nr = pavl_node_new();
                  if (!nr) {
                          nl->u = 1;
                          nl->l = 0;
                          nl->r = 0;
                          pavl_node_put(nl);
                          return 0;
                  }
                  n = pavl_node_new();
                  if (!n) {
                          nl->u = 1;
                          nl->l = 0;
                          nl->r = 0;
                          pavl_node_put(nl);
                          nr->u = 1;
                          nr->l = 0;
                          nr->r = 0;
                          pavl_node_put(nr);
                          return 0;
                  }
                  nl->l = pavl_node_get(l);
                  nl->r = pavl_node_get(m->l);
                  nl->d = a;
                  nl->h = 1+lh;
                  nl->u = 1;
                  nr->l = pavl_node_get(m->r);
                  nr->r = pavl_node_get(r);
                  nr->d = c;
                  nr->h = 1+rh;
                  nr->u = 1;
                  n->l = nl;
                  n->r = nr;
                  n->d = m->d;
                  n->h = 2+lh;
                  n->u = 1;
                  return n;
          } else if ((lh >= mh) && (lh >= rh)) { /* rotate right */
                  unsigned int mrm = 1+(mh > rh ? mh : rh);
                  unsigned int lmrm = 1+(mrm > lh ? mrm : lh);

                  nr = pavl_node_new();
                  if (!nr)
                          return 0;
                  n = pavl_node_new();
                  if (!n) {
                          nr->u = 1;
                          nr->l = 0;
                          nr->r = 0;
                          pavl_node_put(nr);
                          return 0;
                  }
                  nr->l = pavl_node_get(m);
                  nr->r = pavl_node_get(r);
                  nr->d = c;
                  nr->h = mrm;
                  nr->u = 1;
                  n->l = pavl_node_get(l);
                  n->r = nr;
                  n->d = a;
                  n->h = lmrm;
                  n->u = 1;
                  return n;
          } else {		/* rotate left */
                  unsigned int lmm = 1+(lh > mh ? lh : mh);
                  unsigned int lmrm = 1+(lmm > rh ? lmm : rh);

                  nl = pavl_node_new();
                  if (!nl)
                          return 0;
                  n = pavl_node_new();
                  if (!n) {
                          nl->u = 1;
                          nl->l = 0;
                          nl->r = 0;
                          pavl_node_put(nl);
                          return 0;
                  }
                  nl->l = pavl_node_get(l);
                  nl->r = pavl_node_get(m);
                  nl->d = a;
                  nl->h = lmm;
                  nl->u = 1;
                  n->l = nl;
                  n->r = pavl_node_get(r);
                  n->d = c;
                  n->h = lmrm;
                  n->u = 1;
                  return n;
          }
  }


  static struct pavl_node *pavl_add(struct pavl_node *r, int d)
  {
          struct pavl_node *n, *t;

          if (!r) {
                  n = pavl_node_new();
                  if (!n)
                          return 0;
                  n->l = 0;
                  n->r = 0;
                  n->d = d;
                  n->h = 1;
                  n->u = 1;
                  return n;
          }
          if (d < r->d) {
                  t = pavl_add(r->l, d);
                  if (!t)
                          return 0;
                  n = pavl_bal(t->l, t->d, t->r, r->d, r->r);
                  pavl_node_put(t);
                  return n;
          } else if (d > r->d) {
                  t = pavl_add(r->r, d);
                  if (!t)
                          return 0;
                  n = pavl_bal(r->l, r->d, t->l, t->d, t->r);
                  pavl_node_put(t);
                  return n;
          } else {
                  /* dup */
                  r->u += 1;
                  return r;
          }
  }


  static struct pavl_node *pavl_find(struct pavl_node *r, int d)
  {
          if (!r)
                  return 0;
          if (d < r->d)
                  return pavl_find(r->l, d);
          else if (d > r->d)
                  return pavl_find(r->r, d);
          else 
                  return r;
  }


  static void pavl_insert_test(unsigned int n)
  {
          unsigned int i;
          struct pavl_node *nr, *or = pavl_root;

          for (i = 0; i != n; i += 1) {
                  nr = pavl_add(or, keys[i]);
                  pavl_node_put(or);
                  or = nr;
          }
          pavl_root = or;
  }


  static void pavl_find_test(unsigned int n)
  {
          struct pavl_node *r = pavl_root;
          struct pavl_node *f;
          unsigned int i;

          for (i = 0; i != n; i += 1) {
                  f = pavl_find(r, keys[i]);
                  if (!f)
                          printf("pavl find %d failed\n", keys[i]);
          }
  }


  /*
   *
   */

  /*
   * If the algorithm requires allocation, the memory is allocated from
   * this block.  This avoids timing variations due to varying malloc(3)
   * implementations
   */

  union {
          struct hash_node hash;
          struct prbt p_rb_node;
          struct rb_d_node rb_d_node;
          struct pavl_node pavl_node;
  } mem[N+(N/4)];


  static void init_hash_mem(void)
  {
          int i;

          for (i = 0; i != N-1; i += 1)
                  mem[i].hash.free = &mem[i+1].hash;
          mem[N-1].hash.free = 0;
          hash_nodes_free = &mem[0].hash;
  }


  static void init_prb_mem(void)
  {
          int i;

          for (i = 0; i != (N+(N/4))-1; i += 1)
                  mem[i].p_rb_node.l = &mem[i+1].p_rb_node;
          mem[N+(N/4)].p_rb_node.l = 0;
          prbt_free_list = &mem[0].p_rb_node;
  }


  static void init_rb_d_mem(void)
  {
          int i;

          for (i = 0; i != N-1; i += 1)
                  mem[i].rb_d_node.free = &mem[i+1].rb_d_node;
          mem[N-1].rb_d_node.free = 0;
          rb_d_nodes_free_list = &mem[0].rb_d_node;
  }


  static void init_pavl_mem(void)
  {
          int i;

          for (i = 0; i != (N+(N/4))-1; i += 1)
                  mem[i].pavl_node.l = &mem[i+1].pavl_node;
          mem[(N+(N/4))].pavl_node.l = 0;
          pavl_free_list = &mem[0].pavl_node;
  }



  static void init_keys(void)
  {
          int i;

          for (i = 0; i != N; i += 1) {
                  keys[i] = random();
          }
  }


  static void timersub(struct timeval *a, struct timeval *b, struct timeval *diff)
  {
          diff->tv_sec = a->tv_sec - b->tv_sec;
          diff->tv_usec = a->tv_usec - b->tv_usec;
          if (diff->tv_usec < 0) {
                  --diff->tv_sec;
                  diff->tv_usec += 1000000;
          }
  }

  struct {
          int test_tree;
          unsigned int n;
          unsigned int table_size;
  } tests[] = {
          { 1,      100,      100 },
          { 1,      250,      250 },
          { 1,      500,      500 },
          { 1,      750,      750 },
          { 1,     1000,     1000 },
          { 0,     1000,      100 },
          { 0,     1000,       10 },
          { 0,     1000,        1 },
          { 1,     2500,     2500 },
          { 1,     5000,     5000 },
          { 1,     7500,     7500 },
          { 1,    10000,    10000 },
          { 0,    10000,     1000 },
          { 0,    10000,      100 },
          { 0,    10000,       10 },
          { 1,    25000,    25000 },
          { 1,    50000,    50000 },
          { 1,    75000,    75000 },
          { 1,   100000,   100000 },
          { 0,   100000,    10000 },
          { 0,   100000,     1000 },
          { 0,   100000,      100 },
          { 1,   250000,   250000 },
          { 1,   500000,   500000 },
          { 1,   750000,   750000 },
          { 1,  1000000,  1000000 },
          { 0,  1000000,   100000 },
          { 0,  1000000,    10000 },
          { 0,  1000000,     1000 },
          { 1,  2500000,  2500000 },
          { 1,  5000000,  5000000 },
          { 1,  7500000,  7500000 },
          { 1, 10000000, 10000000 },
          { 0, 10000000,  1000000 },
          { 0, 10000000,   100000 },
          { 0, 10000000,    10000 },
  };


  int main(int argc, char **argv)
  {
          struct timeval start, stop, diff;
          /*
           * Set to 1 to run the tests to confirm that the insert
           * does indeed insert all the keys.
           */
          int find = 0;
          unsigned int i;

          init_keys();

          for (i = 0; i != sizeof(tests)/sizeof(tests[0]); i += 1) {

                  init_hash_mem();
                  init_hash_table();

                  gettimeofday(&start);
                  hash_insert_test(tests[i].n, tests[i].table_size);
                  gettimeofday(&stop);
                  timersub(&stop, &start, &diff);
                  printf("ht\t%10u %10u %lu.%lu\n", tests[i].n, tests[i].table_size,
                         diff.tv_sec, diff.tv_usec);

                  if (find) {
                          gettimeofday(&start);
                          hash_find_test(tests[i].n, tests[i].table_size);
                          gettimeofday(&stop);
                          timersub(&stop, &start, &diff);
                          printf("htf\t%10u %10u %lu.%lu\n",
                                 tests[i].n, tests[i].table_size,
                                 diff.tv_sec, diff.tv_usec);
                  }

                  if (tests[i].test_tree) {
                          init_rb_d_mem();
                          rb_d_root.rb_node = 0;

                          gettimeofday(&start);
                          rb_d_tree_insert_test(tests[i].n);
                          gettimeofday(&stop);
                          timersub(&stop, &start, &diff);
                          printf("rb\t%10u %10u %lu.%lu\n", 
                                 tests[i].n, 0, diff.tv_sec, diff.tv_usec);

                          if (find) {
                                  gettimeofday(&start);
                                  rb_d_tree_find_test(tests[i].n);
                                  gettimeofday(&stop);
                                  timersub(&stop, &start, &diff);
                                  printf("rbf\t%10u %10u %lu.%lu\n",
                                         tests[i].n, 0, 
                                         diff.tv_sec, diff.tv_usec);
                          }

                          init_prb_mem();
                          prbt_root = 0;

                          gettimeofday(&start);
                          prbt_insert_test(tests[i].n);
                          gettimeofday(&stop);
                          timersub(&stop, &start, &diff);
                          printf("prb\t%10u %10u %lu.%lu\n", 
                                 tests[i].n, 0, diff.tv_sec, diff.tv_usec);

                          if (find) {
                                  gettimeofday(&start);
                                  prbt_find_test(tests[i].n);
                                  gettimeofday(&stop);
                                  timersub(&stop, &start, &diff);
                                  printf("prbf\t%10u %10u %lu.%lu\n",
                                         tests[i].n, 0, 
                                         diff.tv_sec, diff.tv_usec);
                          }

                          init_pavl_mem();
                          pavl_root = 0;

                          gettimeofday(&start);
                          pavl_insert_test(tests[i].n);
                          gettimeofday(&stop);
                          timersub(&stop, &start, &diff);
                          printf("pavl\t%10u %10u %lu.%lu\n", 
                                 tests[i].n, 0, diff.tv_sec, diff.tv_usec);

                          if (find) {
                                  gettimeofday(&start);
                                  pavl_find_test(tests[i].n);
                                  gettimeofday(&stop);
                                  timersub(&stop, &start, &diff);
                                  printf("pavlf\t%10u %10u %lu.%lu\n",
                                         tests[i].n, 0, 
                                         diff.tv_sec, diff.tv_usec);
                          }
                  }
          }

          exit(0);
  }
0
Reply stephen104 (378) 7/20/2009 5:05:31 AM

Alan Mackenzie wrote:
> In comp.lang.haskell Jon Harrop <jon@ffconsultancy.com> wrote:
>> Alan Mackenzie wrote:
>>> Maybe I'm misunderstanding, but I always thought that "functional"
>>> programmnig was more of a stylistic emphasis, rather than a rigid
>>> definition - calculating functions: good - setting variables and
>>> specifying procedural aspects: considered harmful.  If so, there won't
>>> be any rigid definition.
> 
>> Read "Purely functional data structures" by Chris Okasaki.
> 
> Hmm.  By some strange coincidence, that book doesn't seem to be on my
> bookshelf.

Buy it. Read it.

> Quick excursion via Google.  It seems what Dr. Okasaki is talking about
> in his texts is not data structures which, in some sense, are purely
> functional - it's about using bog standard data structures...

Purely functional data structures have properties like persistence that are
not bog standard.

> in languages 
> (such as as ML and Haskell) which are functional, to whatever degree of
> purity.  Compressing phrases with prepositions and relative pronouns into
> sequences of adjectives and nouns often doesn't work too well in English
> (as contrasted to German, where it's usually OK).
> 
> Which has got precisely what to do with the recent flame fest?  Probably
> not a lot.  Which might be generically similar to what the flame fest had
> to do with.  Or more precisely, people using arcane terminology talking
> crossly at cross purposes with eachother, because they tacitly disagree
> about what the words mean.  Maybe.
> 
> Now given the disadvantages of programming in C (I'm sure we'd agree
> they're substantial), why would anybody want to add the additional
> handicap of doing things "purely functionally" in C?  If you're going to
> accept the shackles of "pure functionalness", you'd be crazy to do it
> in a language where you don't get back more than it costs.

Yes. That is precisely why I do not believe Stephen J Bevan's claims about
his purely functional tree implementations in C that allegedly contradict
my criticism of Real World Haskell.

Given that he hasn't provided the implementations for us to verify his
claims I think it is obvious by now that he was trying to fake it (just
like he did last time around).

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/20/2009 5:08:22 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> Yes. That is precisely why I do not believe Stephen J Bevan's claims
> about his purely functional tree implementations in C that allegedly
> contradict my criticism of Real World Haskell.

There is no reason you should believe without testing it yourself
(something you could do without my C code) but then ...

> Given that he hasn't provided the implementations for us to verify
> his claims I think it is obvious by now that he was trying to fake it

There is no reason to claim someone is trying to fake it because the
weather was too nice to be stuck inside reading Usenet.  The code has
been posted in <86ljmkdjvo.fsf@dino.dnsalias.com>.  

> (just like he did last time around).

And precisely what does that refer to?
0
Reply stephen104 (378) 7/20/2009 5:14:59 AM

Paul Rubin wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> I disagree. Haskell is genuinely unpredictable:
>> http://www.cs.chalmers.se/~rjmh/Haskell/Messages/Archived.cgi?id=102
> 
> A significant theoretical blemish (shared by almost every other
> language including C and Java),

No:

  "It's impossible to say `this program leaks space', because whether a
program leaks or not depends on the evaluation order. In practice, a
program that has been space-debugged under GHC may leak like a sieve under
HBC -- or even under the next version of GHC!"

You think C programmers worry about new compiler versions introducing
unpredictable memory leaks into their code?

> but it doesn't seem to be a bother in practice:
> 
>
http://www.galois.com/blog/2009/04/27/engineering-large-projects-in-haskell-a-decade-of-fp-at-galois/

That is an advertisement for Galois' consultancy services.

Hence they repeatedly refer to themselves as "experts". If Don Stewart is an
expert, why did he not know that array update is O(n) when I brought it up
recently?

Regarding their unverifiable claims about large engineering projects done in
Haskell, why are there no testimonials from happy customers?

Why are they so vague and evasive, e.g. with statements like "fast enough
for the majority of things"? Exactly what "things" have they even
attempted?

Don Stewart is deliberately practising bad science: he starts with the
conclusions he wants to draw and generates unverifiable evidence pointing
at his conclusion. When I question his claims he bans me from forums
instead of justifying himself. There is only one possible reason for this
kind of one way communication: it is advertising.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/20/2009 5:49:02 AM

Jon Harrop wrote:

> That is an advertisement for Galois' consultancy services.

Of course noone else here could be accused of advertising could
they? Sheeesh!

Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/
0
Reply erikd (176) 7/20/2009 7:39:49 AM

On 64-bit Debian etch'n'half on a twin quadcore Xeon workstation, your code
just segfaults:

$ gcc -g -Wall -O3 jon.c -o jon
jon.c: In function ‘rb_d_tree_insert_test’:
jon.c:329: warning: unused variable ‘dup’
jon.c: In function ‘rb_d_tree_find_test’:
jon.c:339: warning: unused variable ‘found’
jon.c: In function ‘ocaml_hash_int’:
jon.c:372: warning: unused variable ‘i’
jon.c: In function ‘hash_insert’:
jon.c:407: warning: left-hand operand of comma expression has no effect
jon.c:402: warning: unused variable ‘head’
jon.c: In function ‘hash_find’:
jon.c:433: warning: left-hand operand of comma expression has no effect
jon.c: In function ‘hash_find_test’:
jon.c:460: warning: unused variable ‘found’
jon.c:459: warning: unused variable ‘l’
jon.c:459: warning: unused variable ‘head’
jon.c:458: warning: unused variable ‘e’
jon.c:457: warning: unused variable ‘h’
jon.c:456: warning: unused variable ‘b’
jon.c: In function ‘main’:
jon.c:1316: warning: implicit declaration of function ‘gettimeofday’
jon.c:1207: warning: array subscript is above array bounds
jon.c:1229: warning: array subscript is above array bounds
$ ./jon
Segmentation fault

I can run your tests in 32-bit and the results do seem to confirm what I
said. Specifically, hash tables are 10x faster than purely functional trees
for a wide range of tasks.

However, I note that swapping the order of the tests over to place the hash
table last, after the trees have warmed the cache, makes the hash table run
many times faster in the initial tests.

Stephen J. Bevan wrote:
> b) I want to avoid any possible complaint that re-sizing is the cause
>    of any performance issues with the hash table.

I think there is a much stronger complaint for not resizing the hash table.
Moreover, you're not using enough buckets/element in any of the tests.

On the other hand, I think the sorted ints you are inserting into balanced
trees is worst case for them: you might try random ints to make the trees
faster. Also, you're using (untested?) reference counting which is
notoriously slow compared to a real GC.

> 2. for n >= 100,000 and more obviously n >= 1,000,000 the results
>    favour a hash table that has sufficient buckets to avoid the effect
>    of collisions coming in to effect (A) with the trees being at least
>    an order of magnitude worse.

This is the effect I was referring to.

> For F = 10 the weak claim is true in the range {1..100000}.  I'm using
> F = 10 here because while the hash table is is up to 5x faster than
> the trees for some values of n, the hash table is also up to 6x slower
> than the trees for some values of n.

So we agree that hash tables are up to 10x faster than purely functional
trees and, therefore, that the claim in Real World Haskell is wrong?

> a) one can at any time allocate a 40MB chunk of physically
>    contiguous memory to hold the new buckets.  Such an allocation is
>    unlikely to succeed.

I regularly rely upon allocations orders of magnitude larger than that. Why
do you think you cannot reliably allocate 40Mb?

> Thus kernels often to use fixed size hash tables and :-
> 
> a) limit the number of elements to avoid the above behaviour thus
>    requiring re-compilation if you actually need a bigger limit.
>    Somewhat problematic if ou are trying to sell a single product to
>    multiple customers.
> 
> b) allocate the maximum number of buckets statically -- somewhat
>    problematic when you have multiple tables (session table, route
>    cache, ARP table, bridge table, IPsec SA map) and different
>    cusomers want to maximize the size of different tables.
> 
> c) use some kind of keyed hash to thwart attackers from causing a
>    problem even when the number of nodes is << the number of buckets.
> 
> d) do nothing and exhibit dramatic performance problems.

Why not just use one of the hash table implementations that guarantees O(1)
for every insertion?

Finally, I object to the idea of crippling the hash table in order to
represent worst case behaviour. If you want to analyze worst case
behaviour, choose an input to the *same implementation* that exhibits the
worst case behaviour.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/20/2009 8:14:26 AM

Jon Harrop <jon@ffconsultancy.com> wrote:
> Stephen J. Bevan wrote:
>> a) one can at any time allocate a 40MB chunk of physically
>>    contiguous memory to hold the new buckets.  Such an allocation is
>>    unlikely to succeed.
> 
> I regularly rely upon allocations orders of magnitude larger than that. Why
> do you think you cannot reliably allocate 40Mb?

Pay attention Jon:

  "In the context I'm interested in (kernel) re-sizing a 10,000,000
  entry hash table is not really an option because it assumes :-

  a) one can at any time allocate a 40MB chunk of physically
     contiguous memory to hold the new buckets.  Such an allocation is
     unlikely to succeed. "

He's writing OS kernel code where you can never assume the
availability of significant amounts of contiguous memory: Even if it's
available it's probably fragmented.

> Finally, I object to the idea of crippling the hash table in order to
> represent worst case behaviour. If you want to analyze worst case
> behaviour, choose an input to the *same implementation* that exhibits the
> worst case behaviour.

Kernels have to care about worst case behaviour. You might not: choose
your algorithms approriately. Surely this isn't controversial?

Phil

-- 
http://www.kantaka.co.uk/ .oOo. public key: http://www.kantaka.co.uk/gpg.txt
0
Reply phil-news (48) 7/20/2009 9:24:02 AM

On Mon, 20 Jul 2009 06:49:02 +0100, Jon Harrop wrote:

>   "It's impossible to say `this program leaks space', because whether a
> program leaks or not depends on the evaluation order. In practice, a
> program that has been space-debugged under GHC may leak like a sieve under
> HBC -- or even under the next version of GHC!"
> 
> You think C programmers worry about new compiler versions introducing
> unpredictable memory leaks into their code?

Of course not; they're too busy worrying about all of the memory leaks the
programmers introduced manually.

Clearly you don't have to worry about the compiler introducing memory
leaks when the language forces you to perform all memory management
manually. But for non-trivial problems, you often end up being stuck with
a choice between:

a) never free() anything, ever, in case it's still being referenced,
b) copy everything just to be safe, or
c) free() stuff if you think it's safe, and we'll just fix the segfaults
as and when people run into them.

0
Reply nobody (4804) 7/20/2009 11:41:48 AM

Phil Armstrong wrote:
> Jon Harrop <jon@ffconsultancy.com> wrote:
>> Stephen J. Bevan wrote:
>>> a) one can at any time allocate a 40MB chunk of physically
>>>    contiguous memory to hold the new buckets.  Such an allocation is
>>>    unlikely to succeed.
>> 
>> I regularly rely upon allocations orders of magnitude larger than that.
>> Why do you think you cannot reliably allocate 40Mb?
> 
> Pay attention Jon:
> 
>   "In the context I'm interested in (kernel) re-sizing a 10,000,000
>   entry hash table is not really an option because it assumes :-
> 
>   a) one can at any time allocate a 40MB chunk of physically
>      contiguous memory to hold the new buckets.  Such an allocation is
>      unlikely to succeed. "
> 
> He's writing OS kernel code where you can never assume the
> availability of significant amounts of contiguous memory: Even if it's
> available it's probably fragmented.

1. Fragmenting the hash table will solve that problem and still be vastly
faster than any purely functional tree.

2. His tree-based code does not handle fragmentation either.

>> Finally, I object to the idea of crippling the hash table in order to
>> represent worst case behaviour. If you want to analyze worst case
>> behaviour, choose an input to the *same implementation* that exhibits the
>> worst case behaviour.
> 
> Kernels have to care about worst case behaviour. You might not: choose
> your algorithms approriately. Surely this isn't controversial?

Neither controversial nor relevant to my statement about experimental
methodology.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/20/2009 12:14:20 PM

Erik de Castro Lopo wrote:
> Jon Harrop wrote:
>> That is an advertisement for Galois' consultancy services.
> 
> Of course noone else here could be accused of advertising could
> they? Sheeesh!

Sure, we advertise. We sell. We have happy customers. But we also publicly
quote verifiable testimonials and engage people in debate if they question
what we say.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/20/2009 12:28:26 PM

Hello Jon

Jon Harrop wrote:
> On the other hand, I think the sorted ints you are inserting into balanced
> trees is worst case for them:

FWIW with AVL trees sorted data sets are pretty much best case. This is
another good thing about AVL trees.

If you play about with this applet..

  http://www.site.uottawa.ca/~stan/csi2514/applets/avl/BT.html

...you can see that with sorted insertions you always get a perfectly
balanced tree for (2^N)-1 elements. It's a pity there's not a similar
demo for other balancing algorithms (not sure how they perform with
the all too common "accidentally sorted" data sets).

Regards
--
Adrian Hey
0
Reply ahey (217) 7/20/2009 2:04:24 PM

On Jul 20, 1:37=A0am, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> Vend <ven...@virgilio.it> writes:
> > > The BWT challenge.
> > If I understand correctly, the problem with that algorithm in Haskell
> > is that in Haskell array update is O(n), right?
>
> That is not a problem for BWT which can use unboxed arrays.
>
> > If that's the case, I suppose that Clean admits a reasonably efficient
> > implementation of that algorithm without using too much black magic.
>
> The issue with GHC boxed arrays is an implementation shortcoming in
> the GHC garbage collector. =A0It has nothing to do with the language.

Why does that happen?

> Clean's GC might or might not have the same issue.

0
Reply vend82 (230) 7/20/2009 4:08:25 PM

On Jul 11, 2:39=A0pm, Andreas Rossberg <rossb...@mpi-sws.org> wrote:
> On Jul 11, 1:02=A0pm, Vend <ven...@virgilio.it> wrote:
>
>
>
> > > Hindley/Milner style polymorphic type inference - which is what all
> > > those functional languages are based on - does not work for imperativ=
e
> > > features. For an imperative language you are forced to use more ad-ho=
c
> > > and less complete approaches.
>
> > Can you provide an example, please?
>
> The simplest possible example: when you declare
>
> =A0 val x =3D nil
>
> where nil denotes the empty list, then in case x is immutable,
> inference can assign the polymorphic type
>
> =A0 x : List[A]
>
> If x is mutable, it cannot, because that would be unsound.

You could find all the statements that assign to the variable and
choose a type that satifies them all, if it doesn't exist then signal
a static type error.

> Similar
> problems occur with subtyping polymorphism, essentially because
> mutable variables always have to be invariant.

?

> > However, I see no point in making all variables immutable, or even in
> > making variables immutable by default.
>
> The idea is that the language (and its type system) should cleanly
> separate the notions of variable and mutable state. That makes the
> intent clear, allows for more flexible typing, and most importantly,
> avoids accident. That is what functional languages do (all of which
> allow mutable state in one form or the other).

Ok, but I think that the best way to do that is to default to mutable
variables and provide an optional "immutable" ("final", "const",
ecc...) keyword.

The F# (Ocaml?) way of defaulting to immutable and providing an
optional "mutable" keyword is acceptable.

The Haskell way of resorting to state monads for simple sequential
computations seems to me like reinventing the square imperative wheel.

0
Reply vend82 (230) 7/20/2009 4:19:53 PM

Vend <vend82@virgilio.it> writes:
> > The issue with GHC boxed arrays is an implementation shortcoming in
> > the GHC garbage collector. �It has nothing to do with the language.
> 
> Why does that happen?

We just had a discussion of this.  Basically if you update a boxed
array element, the entire array is marked "dirty" and is scanned at GC
time.  There are ways around this in the GC literature but none of
them are pretty.  Upthread there is a url of the relevant item in the
GHC bug tracker.  I don't feel like finding it again.
0
Reply phr.cx (5483) 7/20/2009 4:56:32 PM

On Jul 20, 1:05 am, step...@dino.dnsalias.com (Stephen J. Bevan)
wrote:
> Jon Harrop <j...@ffconsultancy.com> writes:
> > Can you give us the code? I am particularly interested in your purely
> > functional tree implementation in C.
>
> The code is mundane and I would have used email but at least one other
> person asked for it so it is attached at the end of this message.  The
> following puts the code in some context :-

Jon, first thanks for the code and the beautiful write up!

Second, gettimeofday takes 2 arguments

     int
     gettimeofday(struct timeval *tp, struct timezone *tzp);

so you need to pass explicitly pass 0 for the tzp argument. If
you don't it will crash on some systems as it did on mine and
perhaps also this is why it crashed on Jon's 64-bit system.

Third, and unfortunately, gettimeofday is fundamentally flawed
for profiling of this nature. gettimeofday is calendar time and
therefore will include time passed running other processes, at
least in a preemptive OS such as you (we) are using. So sadly
all your timing results (particular for the faster runs ie
the ones with smaller n) are corrupted by whatever arbitrary
stuff was happening on your system at the time you ran the
tests.

You need to either use a profiler or switch to clock() timing.
However, there are many caveats when using clock(). For one,
many systems have a slow clock() of say 100Hz so you will need
to make sure you run a timed code fragment for long enough to
capture a reasonable number of samples. Another problem is
that this scaling will vary depending on n because obviously
the running is a function of n. So you need to scale the number
of timing samples roughly with the inverse expected running
time for a given n. So you need something like this rough code

#define MIN_SAMPLES_PER_N 1000000.0 ;

double timesomething ( int samples, int n, yada yada)
{
   int normSamples = (int)(
      samples * MIN_SAMPLES_PER_N / n + 0.5) ;

   clock_t start = clock() ;

   for ( int i = 0 ; i < normSamples ; ++i ) {
      something(n, yada yada) ;
   }

   clock_t stop = clock();
   double delta = stop - start ;
   delta *= samples / normSamples ;
   return delta ;
}

where that MIN_SAMPLES_PER_N is whatever scale factor gives a
reasonable clock() delta for the iterated something(n) to ensure
reasonable reliability and low systematic bias.

KHD
0
Reply duggar (292) 7/20/2009 6:16:30 PM

Hello Folks,

Adrian Hey wrote:
> FWIW with AVL trees sorted data sets are pretty much best case. This is
> another good thing about AVL trees.
> 
> If you play about with this applet..
> 
>  http://www.site.uottawa.ca/~stan/csi2514/applets/avl/BT.html
> 
> ..you can see that with sorted insertions you always get a perfectly
> balanced tree for (2^N)-1 elements. It's a pity there's not a similar
> demo for other balancing algorithms (not sure how they perform with
> the all too common "accidentally sorted" data sets).

OK, googling around reveals quite a few red-black demo applets, most of
which don't work at all AFAICT. But this one does..

http://www.ibr.cs.tu-bs.de/courses/ss98/audii/applets/BST/RedBlackTree-Example.html

If you try sorted insertion of 15 entries with it you get insertion path
of 6 nodes (vs. 4 with AVL). So on this (admitedly tiny) test red-black
trees don't look very attractive.

But now I remember benchmarked this myself a few years ago..

http://groups.google.co.uk/group/comp.lang.functional/msg/74a422ea04ff1217

... it looks like for growing a tree from large sorted data sets
red-black search paths are about 40% longer than AVL.

Regards
--
Adrian Hey

0
Reply ahey (217) 7/20/2009 7:37:35 PM

Jon Harrop wrote:

> Erik de Castro Lopo wrote:
> > Jon Harrop wrote:
> >> That is an advertisement for Galois' consultancy services.
> > 
> > Of course noone else here could be accused of advertising could
> > they? Sheeesh!
> 
> Sure, we advertise. We sell.

From what I've seen, Don Stewart has advertised far less and contributed
far more to Haskell than you have to either Ocmal or F#.

Erik
-- 
----------------------------------------------------------------------
Erik de Castro Lopo
http://www.mega-nerd.com/
0
Reply erikd (176) 7/20/2009 11:22:25 PM

On Mon, 20 Jul 2009 09:08:25 -0700, Vend wrote:

>> > If I understand correctly, the problem with that algorithm in Haskell
>> > is that in Haskell array update is O(n), right?
>>
>> That is not a problem for BWT which can use unboxed arrays.
>>
>> > If that's the case, I suppose that Clean admits a reasonably efficient
>> > implementation of that algorithm without using too much black magic.
>>
>> The issue with GHC boxed arrays is an implementation shortcoming in
>> the GHC garbage collector. �It has nothing to do with the language.
> 
> Why does that happen?

GHC's boxed arrays are either clean or dirty as a whole. If you modify one
element, the entire array becomes dirty and needs to be re-scanned during
gc.

0
Reply nobody (4804) 7/20/2009 11:58:40 PM

On 17 Jul 2009 18:32:14 -0700, Paul Rubin <http> wrote:
[...]
>  Hash tables are
> evil for programmers care about worst case performance.  Programmers
> who don't care about worst case performance are often being naive.

Users typically worry about typical case performance.  If there is a 
1 in 2^n chance of worst case performance and n is sufficiently large
the user base may never encounter worst case performance.

0
Reply dformosa1 (36) 7/21/2009 2:19:20 AM

Erik de Castro Lopo wrote:
> Jon Harrop wrote:
>> Erik de Castro Lopo wrote:
>> > Jon Harrop wrote:
>> >> That is an advertisement for Galois' consultancy services.
>> > 
>> > Of course noone else here could be accused of advertising could
>> > they? Sheeesh!
>> 
>> Sure, we advertise. We sell.
> 
> From what I've seen, Don Stewart has advertised far less and contributed
> far more to Haskell than you have to either Ocmal or F#.

Get your eyes checked.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/21/2009 6:54:19 AM

David Formosa (aka ? the Platypus) wrote:
> On 17 Jul 2009 18:32:14 -0700, Paul Rubin <http> wrote:
> [...]
>>  Hash tables are
>> evil for programmers care about worst case performance.  Programmers
>> who don't care about worst case performance are often being naive.
> 
> Users typically worry about typical case performance.  If there is a
> 1 in 2^n chance of worst case performance and n is sufficiently large
> the user base may never encounter worst case performance.

Right, and this also arises when choosing a pivot for sorting.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/21/2009 6:55:38 AM

Vend wrote:
> On Jul 11, 2:39 pm, Andreas Rossberg <rossb...@mpi-sws.org> wrote:
>> If x is mutable, it cannot, because that would be unsound.
> 
> You could find all the statements that assign to the variable and
> choose a type that satifies them all, if it doesn't exist then signal
> a static type error.

That is essentially the relaxed value restriction used in OCaml:

# [|[]|];;
- : '_a list array = [|[]|]

Its works fine there but cannot escape compilation units and does not sit
well with other approaches to compilation, e.g. F# cannot use it with its
JIT compilation.

>> Similar
>> problems occur with subtyping polymorphism, essentially because
>> mutable variables always have to be invariant.
> 
> ?

I believe Andreas is referring to something like Java's cock-up where they
made arrays covariant, allowing you to cast from an array of Foo up to an
array of Object and then write an Object into one of the elements of what
is actually a Foo array.

>> > However, I see no point in making all variables immutable, or even in
>> > making variables immutable by default.
>>
>> The idea is that the language (and its type system) should cleanly
>> separate the notions of variable and mutable state. That makes the
>> intent clear, allows for more flexible typing, and most importantly,
>> avoids accident. That is what functional languages do (all of which
>> allow mutable state in one form or the other).
> 
> Ok, but I think that the best way to do that is to default to mutable
> variables and provide an optional "immutable" ("final", "const",
> ecc...) keyword.
> 
> The F# (Ocaml?) way of defaulting to immutable and providing an
> optional "mutable" keyword is acceptable.

That is F# only but it is a non-trivial language construct (I don't write
about it until well into my books) because you need to understand scope and
copying.

For example, something like:

  let mutable n = 0
  n <- n + 1
  List.map (fun m -> n + m) ms

gives a compiler error and you have to explicitly un-mutable "n":

  let mutable n = 0
  n <- n + 1
  let n = n
  List.map (fun m -> n + m) ms

The problem is that "n" is internally represented as an alloca on the stack
frame of the outer functions so it cannot safely be passed elsewhere
because the stack frame it is in might disappear. OCaml essentially turns
refs into mutables when it knows they stay in scope, e.g. to unbox floats
within function bodies.

> The Haskell way of resorting to state monads for simple sequential
> computations seems to me like reinventing the square imperative wheel.

Imperative will always be essential in the real world. As soon as you enter
into Haskell's world of high-level abstractions far removed from the
machinery that evaluates programs you completely lose control of time. Your
programs might very well be "right" in theory but if they will not
terminate before the end of the universe, who cares?

Haskell is history repeating itself. Lispers once spoke of a
mythical "sufficiently smart compiler" that could take their abstract
dynamic code and make it run at a decent speed. Nothing ever came of it.
Haskell just takes that idea even further in the wrong direction.

ML really hits the sweet spot in providing powerful abstractions with
predictable performance. Even in F#, with a JIT compiler, the performance
is extremely predictable once you've mastered a few simple rules.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/21/2009 7:07:26 AM

"David Formosa (aka ? the Platypus)" <dformosa@usyd.edu.au> writes:
> Users typically worry about typical case performance.  If there is a 
> 1 in 2^n chance of worst case performance and n is sufficiently large
> the user base may never encounter worst case performance.

If the input distribution is non-random, then the concept of "1 in 2^n
chance" makes no sense.  The input is what it is.  The application
Stephen was talking about was an OS kernel and as such, you have to
assume that the inputs are being concocted by an attacker specifically
for the purpose of breaking the hash function.  If one out of the 2^n
possible inputs sets off the worse case behavior, then that is the
input that the attacker will send.
0
Reply phr.cx (5483) 7/21/2009 7:28:59 AM

Paul Rubin wrote:
> "David Formosa (aka ? the Platypus)" <dformosa@usyd.edu.au> writes:
>> Users typically worry about typical case performance.  If there is a
>> 1 in 2^n chance of worst case performance and n is sufficiently large
>> the user base may never encounter worst case performance.
> 
> If the input distribution is non-random, then the concept of "1 in 2^n
> chance" makes no sense.

Only if you draw the randomness entirely from the attacker, which would be
stupid...

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/21/2009 8:42:03 AM

Ertugrul Söylemez wrote:
> Jon Harrop <jon@ffconsultancy.com> wrote:
>> > What's wrong with purely functional languages?
>>
>> . Unpredictable performance.
> 
> Wrong.

I just found another interesting example of this in the form of the
interpreters written for the ICFP 2006:

  http://www.cse.unsw.edu.au/~dons/um.html

The Haskell solutions range from 4x to 60x slower than C.

In fact, half of the Haskell solutions are even slower than the C
interpreter interpreting an interpreter!

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/21/2009 12:40:02 PM

Keith H Duggar <duggar@alum.mit.edu> writes:
> Second, gettimeofday takes 2 arguments
>
>      int
>      gettimeofday(struct timeval *tp, struct timezone *tzp);
>
> so you need to pass explicitly pass 0 for the tzp argument. If
> you don't it will crash on some systems as it did on mine and
> perhaps also this is why it crashed on Jon's 64-bit system.

It only takes on argument in the kernel (do_gettimeofday) and when I
moved the code from the kernel to user-space the compiler helpfully
told me that there's no such thing as do_gettimeofday and printk but
not that I was missing an argument to gettimeofday :-<  I should have
used "-Wall" but after fighting and losing a battle with "-ansi" I
just left off everything except -O3.


> Third, and unfortunately, gettimeofday is fundamentally flawed
> for profiling of this nature. gettimeofday is calendar time and
> therefore will include time passed running other processes, at
> least in a preemptive OS such as you (we) are using. So sadly
> all your timing results (particular for the faster runs ie
> the ones with smaller n) are corrupted by whatever arbitrary
> stuff was happening on your system at the time you ran the
> tests.

Single user on my machine only has init the shell and various kernel
processes which are all idle.  If yours has more than that then try
killing them off before running any tests.  I get the same results for
the small tests in single user as I do when running in a bottom half
in the kernel so I really don't think gettimeofday is as fundamentally
flawed as you make out.  If you disagree then perhaps you could post
the results of comparing gettimeofday and your suggested method in
single user mode?
0
Reply stephen104 (378) 7/22/2009 1:38:38 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> On 64-bit Debian etch'n'half on a twin quadcore Xeon workstation, your code
> just segfaults:
[snip]
> $ ./jon
> Segmentation fault

As Keith pointed out the missing second argument to gettimeofday is
probably what causes it.  I can post a diff to fix this an the
warnings if that is in any way stopping you from running the tests on
your preferred platform.


> I can run your tests in 32-bit and the results do seem to confirm
> what I said. Specifically, hash tables are 10x faster than purely
> functional trees for a wide range of tasks.

I'm going to avoid "wide range of tasks" and address this point later
where we can quantify the values of n for which the 10x faster is true.


> However, I note that swapping the order of the tests over to place the hash
> table last, after the trees have warmed the cache, makes the hash table run
> many times faster in the initial tests.

I observe no significant difference if I modify the code to call the
ht test before and after prb in every iteration and then compare the
two ht times.  Perhaps your machine is different or you meant
something different?  If so, please post the code or a diff and the
results.


> I think there is a much stronger complaint for not resizing the hash table.
> Moreover, you're not using enough buckets/element in any of the tests.

You have the code.  You can post your own results for the size you
think is appropriate.


> On the other hand, I think the sorted ints you are inserting into balanced
> trees is worst case for them: you might try random ints to make the trees
> faster.

What ordered ints?  The program fills the keys array with 10,000,000
integers by calling random() and then those keys are then used for
every iteration of every algorithm for that run of the test program to
ensure that all algorithms and all sizes of algorithms get the same
numbers in the same order.


> Also, you're using (untested?) reference counting which is
> notoriously slow compared to a real GC.

If you found a bug in the reference counting by all means point it
out.  As to it being slower, it probably is but since it only
negatively affects the persistent trees and I didn't attempt to use it
as a mitigating factor in any results I didn't think you would mind.
As to why reference counting, there is rarely any other alternative
in kernel code.  Just look at the Linux or BSD kernels.  It is
reference counting everywhere except for a couple of special cases
where "real GC" was used.


>> 2. for n >= 100,000 and more obviously n >= 1,000,000 the results
>>    favour a hash table that has sufficient buckets to avoid the effect
>>    of collisions coming in to effect (A) with the trees being at least
>>    an order of magnitude worse.
>
> This is the effect I was referring to.

This is the same point as below so I'll address it below ...


>> For F = 10 the weak claim is true in the range {1..100000}.  I'm using
>> F = 10 here because while the hash table is is up to 5x faster than
>> the trees for some values of n, the hash table is also up to 6x slower
>> than the trees for some values of n.
>
> So we agree that hash tables are up to 10x faster than purely functional
> trees and, therefore, that the claim in Real World Haskell is wrong?

That supposes that the Real World Haskell was making the strong claim.
If that has been your contention all along then we could have saved
ourselves a lot of time if that had been clear from the start since
there was little chance of the strong claim being anything but false.

I lean towards the weak claim which I think is more interesting since
unless the result is the empty set (i.e. the strong claim) then the we
get some boundary values which determine when persistent trees
"perform competitively".  The range 1 to 100,000 seems to be such a
range unless, as noted above, you want to dispute the numbers and post
your own results.  The range may is only 1% of 1 to 10,000,000 and so
easily be covered by "usually" and "wide range of tasks" but for those
who have more modest needs then 1 to 100,000 may entirely cover their
domain of interest and so they'd be completely satisfied with Claim I.


> I regularly rely upon allocations orders of magnitude larger than
> that. Why do you think you cannot reliably allocate 40Mb?

Context is important.  I do not think you regularly allocate 40MB of
_contiguous_ physical memory in a kernel.  As to the fragmentation
issue you raised in a separate message it requires a certain level of
fragmentation or memory use to cause an attempt to alllocate 10240
contiguous physical pages to fail.  The fragmentation or memory usage
has to be significantly higher to cause an one of 10240 allocations of
one page to fail.


> Why not just use one of the hash table implementations that
> guarantees O(1) for every insertion?

You made the a very similar claim in
<yq6dnXhoV63e9azXnZ2dnUVZ8iidnZ2d@brightview.co.uk> and in a response
<86hbym2i3i.fsf@dino.dnsalias.com> I wrote :-

  Jon Harrop <jon@ffconsultancy.com> writes:
  > Stephen J. Bevan wrote:
  >> I agree re-sizing improves the average case but it cannot guarantee to
  >> improve the worst case.
  >
  > On the contrary, the sole purpose of incremental resizing is to guarantee
  > non-amortized O(1) worst case complexity.

  Do you mean the complexity of insert/search or the complexity of
  something else.  If you mean insert/search then do you have a citation
  for or could you sketch the proof?  If you mean something else then we
  are not talking about the same thing, I'm interested in the complexity
  of insert/search.

I didn't see a followup to this.  If you made one and it simply didn't
make it to my news server then could you post the message ID?  If you
didn't see my message before you can kill two birds with one stone and
address it here.


> Finally, I object to the idea of crippling the hash table in order to
> represent worst case behaviour. If you want to analyze worst case
> behaviour, choose an input to the *same implementation* that exhibits the
> worst case behaviour.

I'm clear that you object to how the worst case was done but I don't
follow what your alternative suggestion is.  So, if you feel some
other way is more appropriate you have the code so you can modify it
as you see fit and post the results.
0
Reply stephen104 (378) 7/22/2009 3:17:33 AM

Jon Harrop <jon@ffconsultancy.com> writes:
> I would rather see a proposed attack on a concrete implementation that
> causes it to exhibit bad behaviour in practice.

http://www.cs.rice.edu/~scrosby/hash/

To quote just one example:

    Bro [15] is a general-purpose network intrusion detection system (IDS)
    that can be configured to scan for a wide variety of possible
    attacks. Bro is open-source and is used in production at a number of
    commercial and academic sites. ...  We have designed attack traffic
    that can make Bro saturate the CPU and begin to drop traffic within 30
    seconds during a 160kb/s, 500 packets/second flood, and within 7
    minutes with a 16kb/s flood.

I.e. they brought a widely deployed security system to its knees using
precisely the type of attack that a real intruder could mount.
0
Reply phr.cx (5483) 7/22/2009 6:39:32 AM

Stephen J. Bevan wrote:
> Jon Harrop <jon@ffconsultancy.com> writes:
>> On 64-bit Debian etch'n'half on a twin quadcore Xeon workstation, your
>> code just segfaults:
> [snip]
>> $ ./jon
>> Segmentation fault
> 
> As Keith pointed out the missing second argument to gettimeofday is
> probably what causes it.  I can post a diff to fix this an the
> warnings if that is in any way stopping you from running the tests on
> your preferred platform.

That seems to have fixed the problem, thanks.

>> However, I note that swapping the order of the tests over to place the
>> hash table last, after the trees have warmed the cache, makes the hash
>> table run many times faster in the initial tests.
> 
> I observe no significant difference if I modify the code to call the
> ht test before and after prb in every iteration and then compare the
> two ht times.  Perhaps your machine is different or you meant
> something different?  If so, please post the code or a diff and the
> results.

Actually I think it was just random noise. On one run:

ht             100        512 0.10
rb             100          0 0.12
prb            100          0 0.36
pavl           100          0 0.38

and on the next the hash table is 9x slower:

ht             100        512 0.9
rb             100          0 0.12
prb            100          0 0.32
pavl           100          0 0.37

>> I think there is a much stronger complaint for not resizing the hash
>> table. Moreover, you're not using enough buckets/element in any of the
>> tests.
> 
> You have the code.  You can post your own results for the size you
> think is appropriate.

I've changed the bucket sizes to the next 2^n with a minimum of 512.

>> On the other hand, I think the sorted ints you are inserting into
>> balanced trees is worst case for them: you might try random ints to make
>> the trees faster.
> 
> What ordered ints?  The program fills the keys array with 10,000,000
> integers by calling random() and then those keys are then used for
> every iteration of every algorithm for that run of the test program to
> ensure that all algorithms and all sizes of algorithms get the same
> numbers in the same order.

My bad. I misread your code.

>> Also, you're using (untested?) reference counting which is
>> notoriously slow compared to a real GC.
> 
> If you found a bug in the reference counting by all means point it
> out.  As to it being slower, it probably is but since it only
> negatively affects the persistent trees and I didn't attempt to use it
> as a mitigating factor in any results I didn't think you would mind.

Crippling the trees in any way weakens the result that trees are often a lot
slower. Also, one might argue that the hash table are benefitting from
appropriate initial sizing rather than having to be resized as they are
built.

I do not believe this undermines our conclusion but other people might
disagree.

>>> For F = 10 the weak claim is true in the range {1..100000}.  I'm using
>>> F = 10 here because while the hash table is is up to 5x faster than
>>> the trees for some values of n, the hash table is also up to 6x slower
>>> than the trees for some values of n.
>>
>> So we agree that hash tables are up to 10x faster than purely functional
>> trees and, therefore, that the claim in Real World Haskell is wrong?
> 
> That supposes that the Real World Haskell was making the strong claim.

The statement in Real World Haskell is:

  "Compared to a hash table, a well-implemented purely functional tree data
structure will perform competitively. You should not approach trees with
the assumption that your code will pay a performance penalty."

They said purely functional trees *will* perform competitively.

> If that has been your contention all along then we could have saved
> ourselves a lot of time if that had been clear from the start since
> there was little chance of the strong claim being anything but false.

Then we only disagree on the interpretation of the quote. I do not believe
that quote can be taken in a weak form. Had they said "can" instead
of "will" it would be a different matter, of course.

> The range 1 to 100,000 seems to be such a 
> range unless, as noted above, you want to dispute the numbers and post
> your own results.

I've made a couple of tweaks. Firstly, using the identity as the hash
function as OCaml does:

$ ocaml
        Objective Caml version 3.11.0

# Hashtbl.hash 0;;
- : int = 0
# Hashtbl.hash 1;;
- : int = 1
# Hashtbl.hash 2;;
- : int = 2
# Hashtbl.hash 3;;
- : int = 3
# Hashtbl.hash 4;;
- : int = 4

Secondly, using 2^n buckets and optimizing your use of %:

        if ((max & (max-1)) == 0)
          b = h & (max-1);
        else
          b = h % max;

In a production-quality implementation you would certainly get the compiler
to generate optimized % code for each possible value of "max" and probably
use primes.

On 32-bit, my results are:

ht             100        512 0.10    *
rb             100          0 0.12
prb            100          0 0.36
pavl           100          0 0.39
ht             250        512 0.12
rb             250          0 0.25
prb            250          0 0.82
pavl           250          0 0.100
ht             500        512 0.19
rb             500          0 0.45
prb            500          0 0.176
pavl           500          0 0.227
ht             750       1024 0.30
rb             750          0 0.71
prb            750          0 0.279
pavl           750          0 0.366
ht            1000       1024 0.35    *
rb            1000          0 0.95
prb           1000          0 0.379
pavl          1000          0 0.512
ht            2500       4096 0.112
rb            2500          0 0.252
prb           2500          0 0.1061
pavl          2500          0 0.1477
ht            5000       8192 0.241
rb            5000          0 0.547
prb           5000          0 0.2336
pavl          5000          0 0.3271
ht            7500      16384 0.446
rb            7500          0 0.890
prb           7500          0 0.3859
pavl          7500          0 0.5432
ht           10000      16384 0.517   *
rb           10000          0 0.1282
prb          10000          0 0.5410
pavl         10000          0 0.7577
ht           25000      32768 0.1283  *
rb           25000          0 0.4020
prb          25000          0 0.16664
pavl         25000          0 0.22588
ht           50000      65536 0.2800  *
rb           50000          0 0.9703
prb          50000          0 0.39346
pavl         50000          0 0.52545
ht           75000     131072 0.5194  *
rb           75000          0 0.16319
prb          75000          0 0.65997
pavl         75000          0 0.86650
ht          100000     131072 0.7058
rb          100000          0 0.23553
prb         100000          0 0.93104
pavl        100000          0 0.121364
ht          250000     262144 0.32679 *
rb          250000          0 0.103711
prb         250000          0 0.338182
pavl        250000          0 0.406064
ht          500000     524288 0.87140 *
rb          500000          0 0.338103
prb         500000          0 0.965224
pavl        500000          0 1.122523
ht          750000    1048765 0.179202 *
rb          750000          0 0.634839
prb         750000          0 1.735125
pavl        750000          0 2.354
ht         1000000    1048576 0.198142 *
rb         1000000          0 0.966824
prb        1000000          0 2.585694
pavl       1000000          0 2.972823
ht         2500000    2500000 0.722702 *
rb         2500000          0 3.368154
prb        2500000          0 8.636683
pavl       2500000          0 9.852120
ht         5000000    5000000 1.527562 *
rb         5000000          0 8.184042
prb        5000000          0 20.748892
pavl       5000000          0 23.579010
ht         7500000    7500000 2.378053 *
rb         7500000          0 13.635193
prb        7500000          0 34.447560
pavl       7500000          0 38.921747
ht        10000000   10000000 3.270208 *
rb        10000000          0 19.524350
prb       10000000          0 49.405162
pavl      10000000          0 55.583302

I've marked the results where hash tables were faster than both purely
functional trees with a "*".

The hash table is now faster than purely functional trees for n>7,500 except
for n=100k where the result for purely functional AVL trees is anomalous.
The hash table is up to 15x faster for larger n.

Moreover, replacing your buckets with resizeable arrays instead of lists
should make your hash tables much faster. I did this in my GC and made it
several times faster overall. In fact, I deliberately introduced collisions
because that improved cache coherence when searching small arrays.

> The range may is only 1% of 1 to 10,000,000 and so  
> easily be covered by "usually" and "wide range of tasks" but for those
> who have more modest needs then 1 to 100,000 may entirely cover their
> domain of interest and so they'd be completely satisfied with Claim I.

I disagree. The errors on these results for small n are so large that the
results are inconclusive.

>> I regularly rely upon allocations orders of magnitude larger than
>> that. Why do you think you cannot reliably allocate 40Mb?
> 
> Context is important.  I do not think you regularly allocate 40MB of
> _contiguous_ physical memory in a kernel.

I missed the context that you were talking about OS kernel code. I had not
considered using purely functional data structures in OS kernel code
before.

>> Why not just use one of the hash table implementations that
>> guarantees O(1) for every insertion?
> 
> You made the a very similar claim in
> <yq6dnXhoV63e9azXnZ2dnUVZ8iidnZ2d@brightview.co.uk> and in a response
> <86hbym2i3i.fsf@dino.dnsalias.com> I wrote :-
> 
>   Jon Harrop <jon@ffconsultancy.com> writes:
>   > Stephen J. Bevan wrote:
>   >> I agree re-sizing improves the average case but it cannot guarantee
>   >> to improve the worst case.
>   >
>   > On the contrary, the sole purpose of incremental resizing is to
>   > guarantee non-amortized O(1) worst case complexity.
> 
>   Do you mean the complexity of insert/search or the complexity of
>   something else.  If you mean insert/search then do you have a citation
>   for or could you sketch the proof?

You can reduce the worst case time for insert and search per bucket to O(log
n) by using an impure tree instead of a list, of course. Then you just
incrementally resize the table itself to get O(log n) worst case insert and
search for the whole hash table:

  http://en.wikipedia.org/wiki/Hash_table#Incremental_resizing

FWIW, cuckoo hashing can apparently provide worst case constant time search:

  http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.14.5337

>> Finally, I object to the idea of crippling the hash table in order to
>> represent worst case behaviour. If you want to analyze worst case
>> behaviour, choose an input to the *same implementation* that exhibits the
>> worst case behaviour.
> 
> I'm clear that you object to how the worst case was done but I don't
> follow what your alternative suggestion is.  So, if you feel some
> other way is more appropriate you have the code so you can modify it
> as you see fit and post the results.

I would rather see a proposed attack on a concrete implementation that
causes it to exhibit bad behaviour in practice. Consider our example here
of storing 32-bit ints with an identity hash function but with hash table
resizes at 2^n-1, for example. How *exactly* could an attacker exploit that
to degrade performance? Can you provide a sequence of keys to insert that
actually makes the hash table slower than the pure trees for any n>100k?

I cannot see how the worst case scenarios (except for resizing) can be an
issue in practice unless your keys are much bigger, in which case you
shouldn't be using a single hash table anyway.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
http://www.ffconsultancy.com/?u
0
Reply jon (3267) 7/22/2009 7:19:17 AM

On 21 Jul 2009 00:28:59 -0700, Paul Rubin <http> wrote:
> "David Formosa (aka ? the Platypus)" <dformosa@usyd.edu.au> writes:
>> Users typically worry about typical case performance.  If there is a 
>> 1 in 2^n chance of worst case performance and n is sufficiently large
>> the user base may never encounter worst case performance.
>
> If the input distribution is non-random, then the concept of "1 in 2^n
> chance" makes no sense.  The input is what it is.  The application
> Stephen was talking about was an OS kernel and as such, you have to
> assume that the inputs are being concocted by an attacker specifically
> for the purpose of breaking the hash function.

If that is the enviroment then one could use a cryptographically
secure hash function, a seed value or a combination of the two.
Indeed it is fairly trival (and good for other resons) to ensure that
the pathalogical value is infeasible for the attacker to know.

>  If one out of the 2^n
> possible inputs sets off the worse case behavior, then that is the
> input that the attacker will send.

Only if the attacker knows the input.
0
Reply