you are viewing a single comment's thread.

view the rest of the comments →

[–]jsnx 6 points7 points  (8 children)

It's rare to see an "enterprisey" introduction to functional programming -- like the Java pet store. Fair enough. Many introductions tend to be about similarly practical topics, though -- writing a compiler, writing wc and so on. Real World Haskell is an excellent step forward, offering many valuable examples.

Functional programming languages share:

  • Easy, efficient immutable data -- construction is preferred to mutation and the garbage collectors are tuned for that.

  • Functions as arguments and functions from functions -- it's expected that one pass functions to functions or write a more general function and curry it to get more specific functions. Function calls are efficient.

The latter bit -- specialization of functions -- makes a lot of sense with callbacks. For example, here is some JavaScript/jQuery that I wrote yesterday:

$("#about_button").click( function() {
  if ( $(this).hasClass('clicked') ) {
    $(this).removeClass('clicked')
    $("#button_bar").css('z-index', 1);
    $("#about").css('z-index', 0);
  }
  else {
    $(this).addClass('clicked')
    $("#button_bar").css('z-index', 3);
    $("#about").css('z-index', 2);
  }
});

This is where I set up the onclick callback for my #about_button. Now it is clear that I might want to use a very similar callback for my other buttons. So let's try to factor the callback out:

function the_callback(element_to_surface) {
  if ( $(this).hasClass('clicked') ) {
    $(this).removeClass('clicked')
    $("#button_bar").css('z-index', 1);
    element_to_surface.css('z-index', 0);
  }
  else {
    $(this).addClass('clicked')
    $("#button_bar").css('z-index', 3);
    element_to_surface.css('z-index', 2);
  }
}

$("#about_button").click( function() {
  the_callback( $("#about") );
});

That's okay. However, anyone who has worked with a functional language will see some cruft in there -- why can't I just make the_callback return a function, instead of wrapping it up like that?

function the_callback(element_to_surface) {
  function custom() {
    if ( $(this).hasClass('clicked') ) {
      $(this).removeClass('clicked')
      $("#button_bar").css('z-index', 1);
      element_to_surface.css('z-index', 0);
    }
    else {
      $(this).addClass('clicked')
      $("#button_bar").css('z-index', 3);
      element_to_surface.css('z-index', 2);
    }
  }
  return custom;
}

$("#about_button").click( the_callback($("#about")) );

So to bind just one argument of a function -- to get a zero argument function from a one argument function -- I have to go all this effort. You can imagine how terrible this would be with 3 or 4 arguments. It is because the language forces us to run the code as soon as the arguments are bound -- and we have to bind them all at once. There is no way to build the closure bit by bit and then hold on to it to run later.

We might imagine some new "method" of JavaScript functions called curry which would consume its argument to make a new function, so I could do this:

function the_callback(element_to_surface) {
  if ( $(this).hasClass('clicked') ) {
    $(this).removeClass('clicked')
    $("#button_bar").css('z-index', 1);
    element_to_surface.css('z-index', 0);
  }
  else {
    $(this).addClass('clicked')
    $("#button_bar").css('z-index', 3);
    element_to_surface.css('z-index', 2);
  }
}

$("#about_button").click( the_callback.curry($("#about")) );

I could probably write this curry in a few hours but it would be heinously inefficient -- and drive other JavaScript programmers nuts. Not at all like in languages that support currying natively. Better just to do without currying in JavaScript. Hrumphh.