[Haskell-cafe] Doubting Haskell

Jefferson Heard jefferson.r.heard at gmail.com
Sat Feb 16 19:27:49 EST 2008

  Since everyone's been focusing on the IO so far, I wanted to take a
quick stab at his mention of "green" vs. OS threads...  I like the
term "green", actually, as it's what my grandmother calls
decaffeinated coffee, owing to the fact that decaf taster's choice has
a big green plastic lid.  Distrust all coffee that comes in a plastic
lid, folks.  Life is better that way...

However, Haskell very much has real, caffeinated parallelism
mechanisms.  There is explicit concurrency, which says that things can
happen at the same time (see Control.Concurrent) and there is the
whole question of Glasgow Parallel Haskell and Data Parallel Haskell,
which I won't really begin to cover, as Manuel Chakravarty and Simon
Peyton Jones will do TONS better at explaining these than I can.  I
will however mention Control.Parallel and Control.Parallel.Strategies,
because they're my personal favorite way of being parallel.

The Haskell thread is semantically much like the Java thread, it's
green, in other words, but you can control the number of real OS
threads that Haskell threads are executed on at the command line.
Thus you might call them "half caffeinated"  But, at least with
Control.Parallel.Strategies, they're SO much easier to use.  There are
a couple of caveats, but I'll give an example first.  Let's say you're
doing some heavy computer graphics, but you're doing it all in
spherical coordinates (I do this all the time, which is why I'm using
it as an example) and before you go to OpenGL, you need to transform
everything into Carteisan coordinates.

vertices :: [GL.Vertex3] -- a list of oh, say, 150,000 vertices or so
in spherical coordinates

sphericalToCart :: GL.Vertex3 -> GL.Vertex3
sphericalToCart (GL.Vertex3 r a z) = (GL.Vertex3 (r * cos a * sin z)
(r * sin a * sin z) (r * cos a))

Now to convert them all, you'd just do a

map sphericalToCart vertices

and that would do a lazy conversion of everything, but since you know
you're going to use all the vertices, strictness is just as well, and
you can do strict things in parallel this way:

parMap rwhnf sphericalToCart vertices

or even more efficiently,

map rwhnf sphericalToCart vertices `using` parListChunk 1024

That'll execute on all cores of your processor and do the same
operation much faster, if you were going to have to do the entire
operation anyway.

-- Jeff

On Sat, Feb 16, 2008 at 5:05 PM, Alan Carter <alangcarter at gmail.com> wrote:
> Greetings Haskellers,
>  I'm a Haskell newbie, and this post began as a scream for help. Having
>  slept on it I find myself thinking of Simon Peyton-Jones' recent
>  request for good use cases. Perhaps a frustrated - and doubting -
>  newbie can also provide a data point. If my worries are unfounded (and
>  I hope they are), I think it's significant that to me, today, they
>  seem real enough. Please understand that I'm not being negative for
>  the sake of it - rather I'm describing what Haskell looks like from
>  the outside.
>  Let me put it this way. Imagine that two weeks ago my forward-thinking
>  and risk-embracing boss asked me to evaluate Haskell for the upcoming
>  Project X. Further imagine that she ensured I was able to sit in the
>  corner emitting curses for the whole two weeks, and on Monday I have
>  to provide my report.
>  At this point, two weeks in, I would be forced to say that I have no
>  reason to believe that Haskell is useful for real world tasks. ghc is
>  an industrial strength compiler for a toy language. While remarkable
>  claims are made for it, in practice even the experts are often unable
>  to implement the most basic behaviours, and where they are able to
>  implement, they find that their program has become so complex that
>  they are unable to describe or discuss the result. Likely this is a
>  deep problem, not a shallow one. The Haskell community is in denial
>  over this, leading to phenomenal time wasting as one goes round and
>  round in circles playing word games with documentation. This risks a
>  return of the chronic embuggerance that we thought we'd escaped when
>  Vista appeared and the set of people who would have to write Windows
>  device drivers reduced to Hewlett Packard employees, Joanna Rutkowska
>  and criminals. When people enthuse about Haskell, we should run a
>  program called Cat.hs from the haskell.org website, throw fruit at
>  them and laugh.
>  Strong words, but in all honesty I *want* to believe, and if I would
>  make such a report I imagine hundreds if not thousands would say the
>  same thing. I'm hoping I'm wrong about this, and what's actually
>  needed is some work on communication (perhaps from a production
>  programming point of view, which I'd be keen to help with).
>  What got me started with Haskell was the video of an Intel employee
>  holding a Teraflops in his hand. I still remember the very silly
>  September 1991 edition of Scientific American, which asked if a
>  Teraflops would *ever* be built. What a stupid question! Stack up
>  enough VIC20s and eventually you'll get a Teraflops. The question
>  should have been "when". Now it's the size of a CD, and only 80 cores
>  are needed. Unfortunately keeping 80 cores running is tricky. I know
>  this from writing some heavy parallel stuff in the mid-90s. It was all
>  quite clever in it's day. Chuck bloated and unguessable CORBA, do
>  something light with TCP/IP (Beuwolf took that to extremes). Neat
>  linkage like rpcgen gave C, so that I could run fast on an SMP Sequent
>  with 30 cores or on a floorfull of about 70 Sun pizza boxen at night.
>  Unfortunately despite having a nice framework, tracing rays is still
>  hard (the rays and medium were... interesting). Making a problem
>  parallel required a sneaky and dedicated person's sincere skull-sweat.
>  Worse, the solutions so produced had a horrible structural instability
>  about them. Just a small change to the requirement could require a
>  computed value where it wasn't needed before, so that it resulted in
>  big changes to the implementation. The skull-sweating would be needed
>  all over again. (Remember that the big point about objects, which e.g.
>  Booch always emphasized, was that a well chosen set of classes maps
>  well to the domain and so reduces such structural instability.) Even
>  then, it was devilish hard to keep 70 "cores" busy.
>  So watching the Intel guy got my klaxons going. We now need to be able
>  to do parallel with ease. Functional programming just got really
>  important. It's years since I last played with Scheme, but I quickly
>  moved on because I could see the "which Scheme" problem becoming a
>  millstone round everyone's necks outside of research contexts. Ditto
>  Lisp. So Haskell. Grown-up compiler, one standard and (apparently) a
>  decent corpus of example code and tutorials. I might be an imperative
>  programmer, but I do lapse - for example I find it very easy to
>  generate swathes of cross referenced documentation using m4. My head
>  goes kind of weird after a few hours, such that m4 seems sane and it's
>  the rest of the world that's ungainly, so maybe it should be banned
>  like DMT, but I like it. I felt able to enter the functional world.
>  I'll omit the first week of suffering, which I see is a well
>  documented rite of passage. (Although most evaluators will have left
>  the building by the end of week one so it's not helping popularity.
>  Perhaps there could be Squires of the Lambda Calculus who haven't done
>  the vigil, mortification of flesh and so on?) Eventually a 3 page
>  introduction on the O'Reilly website together with a good document
>  called "Haskell for C Programmers" got me to the point where I could
>  access "Yet Another Haskell Tutorial", and I was away... for a bit.
>  After a while I'd written some malformed horrors as answers to
>  exercises, and was telling myself that it's probably just an edge
>  effect - deep within a real Haskell program the ugliness would be
>  invisible, tucked away in Ugly.hs. Then I discovered wxHaskell and got
>  very excited. I really like wxWidgets, and I know it well. If I could
>  play with some Haskell which manipulates wxWidgets I'd progress very
>  quickly! I even have a recent C++ wxWidgets  program which was
>  annoying me as I wrote it because of the boilerplate. Great! I can
>  play with type inference and mutter "about bloody time" with a smile
>  on my face. Eventually I got a mix of wxWidgets 2.6.3, wxHaskell from
>  darcs, ghc 6.6 running on my Mac, almost exactly as that permutation
>  was described on the website, and I was off.
>  Within a few hours I had a nice frame, with 10 text controls and
>  legends populating it. It already took less lines than C++, and then I
>  discovered how to bundle all the text controls into a tuple to pass
>  them around, and define some "getters" to access the tuple. My line
>  count shrunk to what it "should" be - that is, something Kolmogorov
>  wouldn't laugh at but is unattainable in C++. I had an onOpen which
>  popped up a dialog and got a filename from the user, with all the
>  properties filled in right. I proved that I could update the values in
>  the text controls from the onOpen. Great. Next, translate the bit that
>  says (pseudocode):
>   if(attempt_file_open)
>     if(attempt_file_read)
>       process
>  That's it. No fancy, complex error messages. Just check the error
>  returns and only proceed if I have something to proceed with. Like
>  grown-ups do. I *will* check my error returns. I have tormented too
>  many newbies to *ever* consider doing anything else. If I cannot check
>  my error returns I will not write the program. This is production
>  programming 101, and I suspect that there's a real issue with
>  priorities between the traditional Haskell community and production
>  programmers.
>  So the time of madness began. I could find examples which did:
>   if(attempt_file_open)
>     attempt_file_read
>     process
>  Which is useless. Other examples did:
>   attempt_file_open
>   if(attempt_file_read)
>     process
>  Which is also useless. So I'm looking through the wxHaskell examples.
>  They're all contrived, using very high level functions to (for
>  example) read a complete image structure from a named file, which as
>  one function had one possible source of errors. I go back to scanning
>  and Googling like crazy. Eventually I notice a bit in "Yet Another
>  Haskell Tutorial" - page 65 - which introduces "bracket", immediately
>  explains that it is useless for my (very common) need, and refers the
>  reader to Section 10 - "Advanced Techniques". The author of this
>  excellent document hasn't yet written Section 10. I wonder why. I
>  pause to examine bracket some more. I really can't tell if the
>  "always" clause gets called if the initialization fails. From the use
>  with file opening it looks like it isn't (or the handle to be closed
>  would be invalid) but that wouldn't help if the initializer had two
>  steps, e.g. called socket(2) and bind(2). This is the kind of thing
>  good production programmers get really het up about.
>  I'm still grovelling through reams of stuff, trying to find out how to
>  open *and* read a file in a grown up way, and I find various programs
>  on haskell.org. There's an implementation of cat(1)! That's the thing!
>  A file concatenator must be able to open *and* read it's file. Eagerly
>  I download it. Curiously there doesn't seem to be any error handling.
>  I compile it and point it at a non-existent file. The program crashes.
>  Horribly. So much for Cat.hs. I feel glad I hadn't been able to cope
>  with the video of Simon Peyton-Jones OSCON talk, because the camera
>  operator kept filming his face while he's gesturing at the specific
>  line of code he's talking about with a pointer! After seeing Cat.hs do
>  essence of FAIL just opening a file, claims that Haskell could serve
>  as a scripting language suitable for the crew of the Black Pearl in
>  yonder corner to use would pain me.
>  Now I'm getting cross and turned off the whole business.  I've been
>  here before, grovelling through reams of stuff, trying to find
>  something out while each example is contrived to side-step the
>  problem, half-baked and useless, evasive or referencing non-existent
>  documentation. All I need to make the experience complete is a certain
>  firm's trademarks gratuitously embedded in the text at least once on
>  every line. Then I'd be nauseous by now too.
>  Finally I found an uncommented example with no discussion called Hedi.
>  This seems to be doing exception handling, but what it is doing, how,
>  why, what can raise them, so on and so forth would presumably be
>  covered in the "too complex to describe" bit of "Yet Another Haskell
>  Tutorial". I tried to understand it from first principles, looking at
>  the Type theology for the exceptions and various calls, but while I
>  have the cup of tea I lack the necessary Total Perspective Vortex. I
>  felt no confidence trying to even cut and paste it.
>  So question number one: Please - how do I do this?
>  Somehow I doubt that wrapping the complexity of opening a file *and*
>  reading it in a grown up way and then documenting idioms that use the
>  wrapper would help. If it would, the wrapper and doco would already
>  exist. That implies that the complexity doesn't stack. If I get to the
>  point where I can open a file *and* read it in a grown up way, and
>  then I need to (say) verify a version number from the file:
>   if(attempt_file_open)
>     if(attempt_file_read)
>       if(version_ok)
>         process
>  Would I need to completely restructure my program? I suspect so. But
>  it's worth bringing it up. Question number two: Might wrapping the
>  indescribable complexity of the most basic operations make it possible
>  to publish and discuss some idioms which accomplish them? I'd be quite
>  happy with a voodoo idiom for now. I know someone who (20 years on)
>  still doesn't understand pointers to functions. She still uses
>  qsort(3) by rote, and it works for her. That will do for beginners.
>  My biggest worry is that there's a really bad trade-off going on here.
>  Sure, the structural instability of imperative parallel algorithms can
>  be reduced, but at the cost of adding structural instability to
>  everything else! TANSTAAFL and the lump in the carpet always goes
>  somewhere. I read one chap who complained that in order to add one
>  single line of debug he had to completely restructure his entire
>  program, and then the line count was as big as an imperative language
>  would be. Plus a world more complex I bet. It's this TANSTAAFL that's
>  making me a non-believer.
>  So question number three (rhetorical): What would have happened if
>  Codd and Date had tried to make SQL a general purpose programming
>  language? Sequential file handling would have been impossible for all
>  practical purposes, so no-one would have got the benefits of set
>  theory (oh sorry relational calculus) and our most successful
>  intentional language would have been stillborn. We'd still be using
>  Which leads to question number four: Why not do one job well? Limit
>  parallelism to a single SMP machine where there are no comms to fail
>  and failures which do occur will justify the OS chucking the whole
>  process. Make an interface so that Haskell can be called from C++ or
>  Java, with a simple IDL that can marshall nested structs, list<>s,
>  map<>s and vector<>s in and out. Then we can get on with writing
>  ambitious pure computations with names like sortOutRawCatScanData,
>  tersely and in easily parallelizable ways, like we embed SQL to get
>  certain specialist jobs done.
>  Then when all this was going on, question number five appeared: What
>  the hell are these "lightweight Haskell threads"? Are they some kind
>  of green threads running non-preemptively inside a single OS thread?
>  Are they OS threads that could run concurrently on multi-core
>  hardware? If they are green threads (and it sounds like they are) then
>  this is all an academic exercise which has no production application
>  yet.
>  I'm still hoping that this is solvable. That the instinctive
>  priorities of production programmers are just different to those of
>  researchers, and in fact it *is* possible to open a file *and* read
>  it, checking *both* error returns, without being driven insane. If so,
>  I sincerely suggest an example or two, like the small but well formed
>  programs in K&R, Stroustrup or Gosling saying things like:
>   if((fp = fopen(...)) != NULL)
>   {
>     if(fgets(...) != NULL)
>     {
>       printf(...);
>     }
>     fclose(...)
>   }
>  Best wishes - and still hoping I'm wrong after all
>  Alan Carter
>  --
>  ... the PA system was moaning unctuously, like a lady hippopotamus
>  reading A. E. Housman ..."
>   -- James Blish, "They Shall Have Stars"
>  _______________________________________________
>  Haskell-Cafe mailing list
>  Haskell-Cafe at haskell.org
>  http://www.haskell.org/mailman/listinfo/haskell-cafe

I try to take things like a crow; war and chaos don't always ruin a
picnic, they just mean you have to be careful what you swallow.

-- Jessica Edwards

More information about the Haskell-Cafe mailing list