Anonymous functions and closures
I should have been saying "anonymous functions" because the sample code works without closures. But here's the quick overview.
When I talk about anonymous functions I just mean that you have functions that you know about by reference, not name. If the anonymous functions "close over" some private, local environment, they become closures. (More on what that means in a second.) Whether or not an anonymous functions become closures depends entirely on your language. They do in, say, JavaScript. They do not in C.
Now what happens in JavaScript (and most other modern languages with anonymous functions)? Well most variables are
lexically scoped (lexical literally means "of the text"), the scope of the variable is defined by a block of text. So when the function that refers to that variable is returned elsewhere, from within that copy of the function that variable continues to have its old environment. You can have multiple copies of a function, each of which carries a different local environment. The function can use this local environment to keep track of what is happening. (Warning, JavaScript does this slightly differently than most others, I'll clarify that later.) [link|http://www.perlmonks.org/?node_id=50132|http://www.perlmonks.org/?node_id=50132] demonstrates one abuse of this in Perl - figure out how that code works and you definitely have the idea of closures down. (But usually you don't use them like that...)
By contrast what happens in, say, C or Emacs Lisp? You have anonymous functions. You can call them. But when you do, they've lost the local environment that they were created with.
Of the two approaches that were offered, Aristotle's needs closures to work - which stylesheet you're currently on is kept in private state in a closure. By contrast my approach didn't need closures, it only needed anonymous functions.
Now I gave a warning that JavaScript does things differently from most others? The difference is simple. Consider the following code in Perl:
\n# I'm trying to make this match the JavaScript\nsub curry_all {\n my ($fn, @items) = @_'\n my @curried;\n for (my $i = 0; $i < @items; ++$i) {\n my $item = $items[$i];\n push @curried, sub {$fn->($item, @_)};\n }\n return @curried;\n}\n
And the apparent equivalent in JavaScript:
\n// This doesn't work very well..\nfunction curry_all (fn, items) {\n var curried = [];\n for (var i = 0; i < items.length; ++i) {\n var item = items[i];\n curried.push(function (other_arg) {fn(item, other_arg)});\n }\n return curried;\n}\n
In Perl the result is an array of functions with the different items pre-bound as the first argument. In JavaScript the result is an array of functions with the last item pre-bound as the first argument.
The reason why Perl (and most other languages) works how it does is that $item has a lexical scope of the one loop iteration, so each iteration through the loop gets a new $item variable, so each closure has a different copy of $item.
But in JavaScript for reasons that I do not understand, they stick their definition of a "local environment" on that invocation of the function. So even though item is a variable in the lexical scope of the loop inside the function, in JavaScript the created closures all see the same item variable, which has the last value assigned to it (from the last pass through the loop).
The fix in JavaScript looks like this:
\n// This works\nfunction curry_all (fn, items) {\n var curried = [];\n for (var i = 0; i < items.length; ++i)\n curried.push(curry(fn, items[i]));\n return curried;\n}\n\n// This really needs to be its own function\nfunction curry(fn, item) {\n return function (other_arg) {fn(item, other_arg)};\n}\n
Cheers,
Ben
PS We say that you "curry" a function when you pre-bind variables. The term is named after Haskell Curry who demonstrated that in a language with functions as a datatype, anything that you can accomplish with functions that accept multiple arguments can be accomplished with currying. And the language Haskell is, of course, also named after him. (Haskell only has functions of a single variable, and implicitly curries everywhere.)