Sunday, January 9, 2011

Higher order functions as a building block for readable code

If you use a language like Ruby it's trivially easy to make DSLs and all this sweet-looking meta-programming stuff - you're lucky to be close enough to Lisp so you get the code that you can tweak the code before it's run. (attr_accessor, for example, is conceptually nothing more than a macro that expands into the reader and writer methods).

In Lua, you do not have that luxury. Well, you can have - if you install Metalua. But for my purposes this is usually a bit of using a nuke to shoot the pigeons. I want to minimize the number of dependencies - consequently, I try to rely on the stock 5.1 install as much as possible.

So, how does higher order functions help, you not getting a chance to do a "meta" code run ?

Because they allow the deferred execution.

This is a trick I used with this construct in gliese:


mongrel2connect {
sender_id = '558c92aa-1644-4e24-a524-39baad0f8e78',
sub_addr = 'tcp://127.0.0.1:8989',
pub_addr = 'tcp://127.0.0.1:8988',

-- Routing

get { "/", default_page, params = {
test = { optional },
}
},
get { "/foo", foo_page, params = {
test = { mandatory },
}
},
-- Anything else just redirect to root
get { ".*", redirect_request_to("/") },
}


mongrel2connect is a "real" function (the one that actually gets called and runs the loop servicing the requests)

whereas the "get" is the higher-order function. It returns a function that can be used to match the request against the supplied pattern to see if it is routable to the handler, and as well to check the parameters.

So, while the arguments for the mongrel2connect are calculated before the call to that happens, they can be used afterwards - thanks to the fact that the arguments do not do any action - but merely return the code to do the action.

This is a neat trick that allows me to make very readable code (at least for me:-) - essentially a DSL that you squeeze into a Lua table.

No comments: