<table cellspacing="0" cellpadding="0" border="0" ><tr><td valign="top" style="font: inherit;">Before anything else, I want to point out that I have no intention to confront your community, or denigrate Haskell. A few days ago I answered an email from a Clean programmer on something related to Clean. He was worried that Clean team could give up its good work, and Clean could disappear; therefore, he was thinking about switching to Haskell. Since I thought that my email could be of interest for the Clean community, I posted it in the -- small-- Clean list :-(Clean is not as popular as Haskell). I received a lot of furious and offensive private emails for suggesting the Clean programmer to stick with Clean. However, I also received a very polite, humorous, and illuminating private email from a person who seems to work at Microsoft. His name is Simon Peyton-Jones. He<br>urged me to post my comments on a Haskell cafe. He also filed one of my comments as a
 bug in a Haskell bug track. Here is a couple of snippets from his email:<br><br>--- I think it's v bad that a straightforward program runs so slowly, and it's certainly true<br>that this is an area we could pay more attention to.<br><br>--- Meanwhile, I'm curious: are the arrays in Philippos's program strict?&nbsp; Or lazy?&nbsp; If strict,<br>that's a pretty big difference.<br><br>Therefore, here are my comments, with a lot of code. <br><br>A few months ago I came accross an unpublished article about a novel genetic programming system. The system was coded in Larceny Scheme. I translated it to Clean and to Haskell. Unhappily, I cannot post the program here because it is very large, and the authors of the original Lisp program don't want me to divulge it before they see in in a printed page of a Journal. Therefore, I wrote an empty genetic programming framework, just to compare languages. Comparing Clean and Haskell, I noticed:<br><br>1 -- Clean
 compiler almost never let me do very stupid things, like trying to unbox a tree, or to write in a closed file (I will post an example of this in a near future). For instance, Clean compiler would never swallow something like the code below:<br><br><br>import Control.Monad.ST<br>import Data.Array.ST<br>import Data.Array.Base<br>import System.Random<br><br>data Op = AND | OR | NOT;<br>data Tree= L Double | T Op [Tree]<br><br>main = print $ runST<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (do arr &lt;- newArray (1,2000000) (L 0.0) :: ST s&nbsp; (STArray s Int Tree)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go&nbsp; arr 2000000 0.0 )<br><br>go ::&nbsp; STArray s Int Tree -&gt; Int -&gt; Double -&gt; ST s
 Double<br>go a i acc<br>&nbsp; | i &lt; 1 = return acc<br>&nbsp; | otherwise=do <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; b &lt;- unsafeRead a i {- readArray a i -}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; writeArray a i (setDouble ((getDouble b)+3.0))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c &lt;-&nbsp; readArray a i <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; go&nbsp; a (i-1) (acc+ (getDouble c))<br><br>-- What I really need is a random index in Haskell.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>getDouble (L r)= r<br>getDouble _ = 0.0<br><br>setDouble r= L r<br><br>2 -- Safety does not cost much in Clean. For instance, removing array boundary check does not seem to affect Clean. I believe that it does not affect Haskell either,
 but I have not verified this point.<br><br>3 -- Haskell seems to loop more often than Clean. For instance, Haskell may loop if I change function mutate to<br><br>mutate e (L i) xs = (e, xs)<br>mutate e t (y:ys) = ins t (rnLen t y, ys) where<br>&nbsp; ins (T p (L i:xs)) (0, st)=(T p (e:xs), st)<br>&nbsp; ins (T p (t:xs)) (n,(r1:rs)) | n &gt; 0=<br>&nbsp;&nbsp;&nbsp; let (T p mt, s2)= ins (T p xs)(n-1, rs)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in (T p (t:mt), s2)<br>&nbsp; ins (T p (t:xs)) (n,(r1:rs))<br>&nbsp;&nbsp;&nbsp; | rn 2 r1== 0= (T p (e:xs), rs)<br>&nbsp;&nbsp;&nbsp; | rn 2 r1== 1= let (xpr, st)= mutate e t rs<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in (T p (xpr:xs), st)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>This might be a bug in my implementation of show Tree. It would be great
 if you people could "show" me what I did wrong.<br><br>4 -- On the plus side, there are libraries in Haskell that seem to behave better than the Clean equivalent libraries. This could be explained by the fact that there are a lot of people coding Haskell libraries, while Clean team seems to be reluctant in accepting libraries from outsiders. For instance, lethevert made a very important improvement in ObjectIO (changing fonts in edit text field), but it was never incorporated into Clean (yes, I wrote a lot of emails to Clean&nbsp; team about it). Last year, when I was learning Clean, I discovered that many of my professors and teachers are presbyopic. Therefore, it would be a good policy to use very large fonts for homework. I only succeeded in doing it thanks to lethevert. In the case of the program below, Haskell System.Random library seems to work much better than Clean MersenneTwister.<br><br>5 --- Any improvement in the program below will be
 welcome. The program is already very fast thanks to suggestions I received from the bug track people, and from Peyton-Jones. Function "show" seems to loop if I replace mutate in item 3 for mutate in the code below. <br><br>{- ghc gp.hs -O2 --make -}<br>{- Execute:&nbsp; gp.exe +RTS -sstderr -}<br>import Control.Monad.ST<br>import Data.Array.ST<br>import Data.Array.Base<br>import System.Random<br><br>data Op = AND | OR | NOT;<br>data Tree= L Int | T Op [Tree]<br>psz= 20000<br>thr=4.0<br>gates= [AND, NOT, OR]<br><br>table= [ (False, False, False), (True, False, True),<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (True, True, False), (False, True, True)]<br><br>prt NOT= "NOT"<br>prt OR= "OR"<br>prt AND= "AND"<br><br>instance Show Tree where<br>&nbsp;&nbsp;&nbsp; show (L i) = "L"++(show i)<br>&nbsp;&nbsp;&nbsp; show (T p xs) = (prt p)++(show xs)<br><br>main = do <br>&nbsp;&nbsp; xs &lt;- (rnList (1, 20000)) <br>&nbsp;&nbsp; print&nbsp; $ runST $
 do<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; arr &lt;- newArray_ (1,psz)&nbsp; :: ST s (STArray s Int Tree)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (arr, xs1) &lt;- gen0 arr psz xs<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; g1 &lt;- evolve 30 arr (L 0) xs1; return $ g1 <br><br>gen0 a i xs = if i&lt;=0 then return(a,xs) else do <br>&nbsp;&nbsp;&nbsp;&nbsp; (tree, rs) &lt;- return(rndXpr gates 5 xs)<br>&nbsp;&nbsp;&nbsp;&nbsp; writeArray a i tree<br>&nbsp;&nbsp;&nbsp;&nbsp; gen0 a (i-1)&nbsp; rs<br><br>mutate e (L i) xs = (e, xs)<br>mutate e t (y:ys) = ins t (rnLen t y, ys) where <br>&nbsp; ins (T p (L i:xs)) (0, st)=(T p (e:xs), st)<br>&nbsp; ins (T p (t:xs)) (n,(r1:rs)) | n &gt; 0= <br>&nbsp;&nbsp;&nbsp; let (T p mt, s2)= ins (T p xs)(n-1, rs) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in (T p (t:mt), s2)<br>&nbsp; ins (T p (t:xs)) (n,(r1:rs)) <br>&nbsp;&nbsp;&nbsp; | rn 2 r1== 0= (T p (e:xs), rs)<br>&nbsp;&nbsp;&nbsp; | rn 2 r1== 1= let (xpr, st)= mutate e t rs
 <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; in (T p (xpr:xs), st)<br><br>fxy NOT r= T NOT [L (rn 2 r)]<br>fxy AND st = T AND [L 0, L 1]<br>fxy OR&nbsp; st = T OR&nbsp; [L 0, L 1]<br><br>rndXpr fs&nbsp; beastSz xs= loop beastSz xs where<br>&nbsp; rth s r= s!!(rn (length s) r)<br>&nbsp; loop n (r1:r2:rs)<br>&nbsp;&nbsp;&nbsp;&nbsp; | n&lt;1 = (fxy (rth fs r1) r1, rs)<br>&nbsp;&nbsp;&nbsp;&nbsp; |otherwise= mutate (fxy (rth fs r1) r2) f1 rs<br>&nbsp;&nbsp;&nbsp; where (f1, ys)=&nbsp; loop (n-1) rs<br><br>run (L 0) x y= x -- Interpreter<br>run (L 1) x y= y<br>run (T AND xs) x y = and [run c x y&nbsp; | c &lt;- xs]<br>run (T OR xs) x y= or [run c x y | c &lt;- xs]<br>run (T NOT (t:_)) x y= not (run t x y)<br><br>rn n r= (abs r) `rem` n<br><br>rnLen (T _ s) r= rn (length s) r<br><br>rnList :: (Int, Int) -&gt; IO [Int]<br>rnList r=getStdGen&gt;&gt;=(\x-&gt;return(randomRs r
 x))<br><br>frag&nbsp; (L i)&nbsp; st = (L i, st)<br>frag (T p xs) (r1:r2:rs)<br>&nbsp; | rn 2 r2==0= (xpr, rs)<br>&nbsp; | otherwise= frag xpr rs &nbsp;<br>&nbsp;where xpr= xs!!(rnLen (T p xs) r1) <br><br>crossover e1 e2 rs = ([c2, c1], rs4)&nbsp; where<br>&nbsp;&nbsp; (g1, rs1) = frag e1 rs<br>&nbsp;&nbsp; (g2, rs2) = frag e2 rs1<br>&nbsp;&nbsp; (c1, rs3) = mutate g1 e2 rs2<br>&nbsp;&nbsp; (c2, rs4) = mutate g2 e1 rs3<br><br>nGates (L i)= 0.0<br>nGates (T p xs) = (-0.1) + sum [nGates g | g &lt;- xs]&nbsp; &nbsp;<br><br>fitness tt gt = (ng + 1.0 + sum [ft t | t &lt;- tt]) where<br>&nbsp;&nbsp; ng= nGates gt<br>&nbsp;&nbsp; ft (out, t1, t2) | run gt t1 t2 == out= 1.0<br>&nbsp;&nbsp; ft _ = 0.0<br><br>evolve n p b xs | n &lt; 1 = do<br>&nbsp;&nbsp; (arr, xs1) &lt;- gen0 p psz xs<br>&nbsp;&nbsp; evolve 30 arr b xs1<br>evolve n p b (r1:r2:rs) = do <br>&nbsp;&nbsp;&nbsp;&nbsp; n1 &lt;- return $ 1+(rn psz r1)<br>&nbsp;&nbsp;&nbsp;&nbsp; n2 &lt;- return $
 1+(rn psz r2)<br>&nbsp;&nbsp;&nbsp;&nbsp; g1 &lt;- readArray p n1; g2 &lt;- readArray p n2<br>&nbsp;&nbsp;&nbsp;&nbsp; ([c1,c2], rs) &lt;- return $ crossover g1 g2 rs<br>&nbsp;&nbsp;&nbsp;&nbsp; insrt c1 p 1 psz <br>&nbsp;&nbsp;&nbsp;&nbsp; insrt c2 p 1 psz <br>&nbsp;&nbsp;&nbsp;&nbsp; res &lt;- best 1 b p<br>&nbsp;&nbsp;&nbsp;&nbsp; fitn &lt;- return $ fitness table res<br>&nbsp;&nbsp;&nbsp;&nbsp; if fitn &gt; thr <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; then return res else evolve (n-1) p res rs <br><br>best i res p | i &gt;= psz= return res<br>best i fg p= do <br>&nbsp; g &lt;- readArray p i<br>&nbsp; if (fitness table fg) &gt; (fitness table g) <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; then best (i+1) fg p else best (i+1) g p <br><br>insrt g v i sz | i &gt;= sz = return ()<br>insrt g v i sz = do<br>&nbsp;&nbsp; a &lt;- readArray v i<br>&nbsp;&nbsp; fg &lt;- return $ fitness table g<br>&nbsp;&nbsp; fa &lt;- return $ fitness table a<br>&nbsp;&nbsp; if
 fa &gt; fg then insrt g v (i+1) sz<br>&nbsp;&nbsp;&nbsp;&nbsp; else do writeArray v i g<br>&nbsp;</td></tr></table><br>
      <hr size=1>
Looking for the perfect gift?<a href="http://www.flickr.com/gift/"><b> Give the gift of Flickr!</b></a>