[Haskell-cafe] Why Haskell?

Matthew Bromberg mattcbro at earthlink.net
Sat Jul 22 17:08:27 EDT 2006


I am currently in the middle of a reasonably large software simulation 
of a wireless network that I'm programming
in Haskell and in C.   Progress has been slower than anticipated and I 
occasionally (probably because of looming deadlines)
 ask myself did I take the right approach?

Here are the reasons why I chose Haskell initially
1)  It's mathematical elegance, I thought would lend itself to the 
complex mathematical expressions I am implementing.
2) It rates reasonably high in performance comparisons with other languages
http://shootout.alioth.debian.org/gp4sandbox/benchmark.php?test=all&lang=all
3) It has a very active community who are courteous and quite helpful
4) It has an interactive shell.
5) It integrates easily with C.


The idea would be to implement hooks to some fast matrix libraries and 
some plotting routines in C and then develop the higher level logic in 
Haskell.
Since marshalling arrays and such, is a bit of a pain I structured my C 
matrix library in the form of stack based machine, using reference counting
to handle memory management and to minimize the amount of actual data I 
need to pass between C and Haskell.  This seems to work fairly well.
However I have been somewhat disabused of my original thought about how 
development would proceed.  I had hoped that I could get within a factor 
of two or so of the fast prototyping, development times of a good 
scripting language such as Matlab,  Python or Lua, but I don't think I'm 
achieving this unfortunately.

Here are some reasons why
1) Lack of debugging support.  Yes there are print statements and trace, 
but I would like to set a breakpoint.  It would be nice to do so and 
launch the GHCi interpreter with all the variable context supported.  A 
google search revealed that there is current work on this, but 
unfortunately the package is in cabal, which has spotty support in 
windows it seems.
2) Recompiling binaries (necessary in order to link in foreign object 
code into GHCi) is slow using GHC.  Moreover I have to restart GHCi if I 
want to reload a changed DLL (unless there is a way to unload a DLL in 
GHCi).  It also requires jumping around between several console windows 
to get the job done.  (I'm not using an IDE does one exist?)
3) Lack of automatic type coercion for closely related types.  In 
particular I have to use CInt and CDouble to go into and out of C.  
Unfortunately only a small subset of  library functions will actually 
support CInt so I have to explicitly coerce this values.  I usually have 
a host of compile errors initially because of this silly issue and it 
makes the code ugly.  What would help would be an automatic type 
conversion from CInt to Int and CDouble to Double.  Perhaps some warning 
level could flag these if this were 'too dangerous'.
4) GHCi is really not as useful as I'd hoped.  You can not just cut and 
paste Haskell code from a text file and run it in the interpreter.  
There is also this context issue concerning what modules are actually in 
scope.  So although in Haskell once I import a module, all of its 
functions are in scope, in GHCi, if I load this module only the exported 
functions from that module are in scope.  The result, again, is that I 
can not get an apples to apples idea of what is happening in my code. 
Thus I have been using GHCi primarily as a syntax checker for Haskell 
constructs.
5) Learning new programming patterns may have a role to play, but 
sometimes things like iteration is cleaner than recursion.  I worry 
about performance issues however.  I had to create a 50 Mbyte matrix and 
I used what I thought, initially was an elegant contruction technique in 
Haskell.  Something like this
do
...
    sequence $ [ reffill b s | s <- [0..(fi temits)-1], b <- [0..(fi nc)-1]]
...(push list on to matrix stack)

The refill function generates a matrix based on basestation index b and 
SU index s and pushes it on the Matrix stack in C, inside an IO monad.  
So it returns IO().
The list comprehension ends up doing a cartesian product of all (b,s) 
pairs which in this case is a large number.  fi is my shorthand for 
doing an annoying CInt to Int conversion.  The problem with this code is 
that it takes about 500 Mbytes in memory instead of 50 Mb.  Apparently 
it loads up all the potential IO actions into the huge list before 
executing it, taking the factor of 10 or so hit.  There is probably a 
nice space saving way of doing this, that executes each IO action before 
generating the next one, but I was in too much of a hurry to figure it 
out.  This also makes me wonder about the efficiency of the C 
interface.  Each IO action calls a C function  (using the unsafe 
specifier in the import declaration).  I hope there isn't too much 
overhead with this.  In my case I do almost no marshalling.  Most calls 
have no arguments and no returns, or at most require a handful of CInts 
or CDoubles. 

My application has 60-70% of it's statements in an  IO monad calling 
lots of C code.  I begin to wonder if all those statements shouldn't in 
fact just be in C to begin with.  Thus I begin to wonder why I'm using 
Haskell.  Maybe I just need some encouragement that my choice will pay 
off in the end.


More information about the Haskell-Cafe mailing list