Hacker News new | past | comments | ask | show | jobs | submit login
Haskell comprehension measured through WTF/min (ripplingbrainwaves.blogspot.com)
28 points by nickb on Feb 11, 2009 | hide | past | favorite | 17 comments



You know, funnily, that's one of the things I enjoyed about Ruby most from the get-go: there's a very low incidence of "WTF?"

In Ruby, most concepts that you haven't met before are still intuitive enough to be able to grasp them without being told what they are explicitly. Of course, there are exceptions (inject takes a little getting used to, as do some edge cases with code blocks and lambdas), but take the following example:

  puts Project.find_all_by_created_at(1.month.ago..Time.now).collect(&:name).join(", ")
This uses a few "medium-advanced" ruby concepts, like ORM, ranges of dates, and iterating through a collection and mapping the results of the iteration, and yet even someone who knows zero programming has a chance of figuring out what it does.

Or:

  recent_joiners = project.all_users.select { |user| user.joined_at(project) > 1.month.ago }
All very obvious. I like obvious code. As they say, code should be written for people to read, and only incidentally for machines to execute. Whatever other flaws it may have, Ruby is written for clear, easy reading.

On the other hand, after the Erlang 'discussion' ("Why OO Sucks") Dale Harvey pointed me to this erlang file: http://github.com/daleharvey/erlang_util/blob/e9057208f88ba5...

The density of WTF's in this file is huge. Who can make sense of the following lines without any explanation?

  format([$M|T], {{_,M,_},_}=Dt, Acc) ->
      format(T, Dt, [smonth(M)|Acc]);
Beyond "It's something to do with formatting a date of some sort", it's hard to tell what it does or how. And yet, this piece of code is probably trivial when compared to the ruby code I pasted above.

Personally, I really prefer languages with a low WTF/minute rate right from the start. Then I can measure progress in that language based on what I achieve with it, rather than based on how many hurdles I've jumped to get to square one.


> Personally, I really prefer languages with a low WTF/minute rate right from the start.

I think you are missing the point of the article. The idea is that Haskell taught the author new ways of thinking. It allowed him to see computation in a way that he had never seen before.

This is a good thing. Language features are restricted to one language. New ways of thinking are useful everywhere.


So your point is that these ways of thinking are unachievable without a syntax filled with WTFs? I'm no expert on functional languages like Haskell or Erlang, but somehow that doesn't ring true to me. There's gotta be a way to create languages that provide new ways of thinking while maintaining a clear syntax. Ruby (sorry, that language again), for example, provides a number of functional language features with a very clear syntax.


I don't think any of Haskell's syntax is intrinsically unclear.

If you read the article, you'll notice that most of the WTFs are things like "oh, I never though of abstractions like monads, functors, etc." There is one about the indentation thing, but honestly, braces are probably a WTF to people that only know Python.


I have a hard time figuring out precedence relations when looking at Haskell code. I can't always figure out which are the functions, which are the arguments, and which are the functions passed as argument. The fact that Haskell does not have any punctuation to denote function application obviously has something to do with this.


You don't need syntax for that. Regular function application has the highest precedence and functions always have exactly one argument.


Good to hear. I haven't really had the time to look into Haskell (or Erlang, for that matter). Some day, perhaps...


He also said something about backticks. But they are easy, too.


The syntax in Haskell is very easy, in fact there is much less of it than in Ruby.


> The density of WTF's in this file is huge. Who can make sense of the following lines without any explanation?

  format([$M|T], {{_,M,_},_}=Dt, Acc) ->
      format(T, Dt, [smonth(M)|Acc]);
I assume you mean "Who with zero programming experience can make sense[...]". No argument there.

I know Erlang quite well, and personally I find the dh_date.erl code obvious and beautiful.


No, I mean who with zero Erlang programming experience. Over time, I have programmed in: BASIC, Pascal, C, C++, PHP, Perl, Java, Javascript, Ruby - and that's the languages I actually did stuff in. I am familiar with Python and Lisp as well. And yet this code is not obvious to me.

Of course it's clear to someone who "knows Erlang quite well". But the Ruby code is clear to someone who "doesn't know Ruby at all", that's the difference I was pointing out.


If you have experience in Python then it's clear that the Ruby code won't be hard to understand, because those languages are similar. The Erlang code makes use of pattern-matching, which is mostly used in functional languages. So I think someone with experience in Haskell or O'Caml wouldn't have problems understanding the Erlang code.


Recursion also takes a while getting used to if you don't have a math background. Another issue is the frequent use of abbreviations in functional languages as seen in the Erlang example. A bit more verbosity in function and variable naming is useful to make the true abstractions more clear.

On the other hand swombat's Ruby examples which use mapping, filtering etc. would be more elegant in many functional languages.


Yes. You do not see naked recursion very often in, say, Haskell. Most of the time you use the built-in combinators or roll your own.


> Of course it's clear to someone who "knows Erlang quite well". But the Ruby code is clear to someone who "doesn't know Ruby at all", that's the difference I was pointing out.

In the Ruby example, you name your identifiers "project", "all_users", "select", and "recent_joiners". Even without looking the code, it's pretty obvious what you are doing here -- selecting the users who have recently joined a project. The code doesn't matter, all the clarity comes from the identifiers.

In the Erlang example, you use the identifiers M, T, smonth, Dt, and Acc. It is a bit harder to reason about, because there is no context and your variable names don't mean anything. (Although I can guess that M is a month and Dt is a date.)

Any conclusions you draw from this about Ruby and Erlang are wrong -- the conclusions are about identifier naming. I could just as easily write Ruby that looks like:

   rj = p.users.find { |u| u.join_t(p) > now - 2592000 }
Not as easy to read, is it?


That's not quite true. Identifiers are one thing, but language clarity helps too. For instance, in PHP you might have written:

  $recent_joiners = new Array();

  foreach ($user in $project.all_users) {
    if ($project.join_date($user) > ONE_MONTH_AGO) {
      $recent_joiners.push($user);
    }
  }
That's using fairly clear identifiers, but because of all the boilerplate code noise and the less clear language constructs, it looks less readable. Also, this requires a lot more specific meta-programming (like the ONE_MONTH_AGO constant), whereas the example I pasted uses vanilla Rails.


This is a pain to type in (which is why you shouldn't use PHP), but it's not at all hard to read.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: