An Example of Partial Application in Lua

Today I want to describe an example of partial application when writing Lua functions. Ours will be a function which accepts two parameters:

  1. A function.
  2. A table of values which are given to that function.

Note: The first argument can also be something like a table which implements the __call() metamethod. It can also be anything which is somehow applied to the values of the table, e.g. a string concatenated to each value. We’re using a function for simplicity.

For this article we’ll be implementing a simple table.map() function. It will take a function and a table, and return a new table with the results of calling that function on each value of the original table.

The Implementation


function table.map(f, t)
    local function apply(values)
        local results = {}
        for index,value in pairs(values) do
            results[index] = f(value)
        end
        return results
    end

    if t then
        return apply(t)
    else
        return apply
    end
end

An example use:


local numbers = {1, 2, 3}
local function double(x) return x * 2 end
local x = table.map(double, numbers)

for _,n in ipairs(x) do print(n) end

-- Prints:
--
-- 2
-- 4
-- 6

Details

There’s nothing novel or clever going on here. But let’s re-examine the definition of table.map(). A much more simple implementation would be this:


function table.map(f, t)
    local results = {}
    for index,value in pairs(t) do
        results[index] = f(value)
    end
    return results
end

But instead we wrap that logic into the inner function apply() which when then call from within table.map(). What we gain from this approach is illustrated by the return value of table.map(). When given both arguments it returns a table of results.

However, if we call table.map() with only the first parameter then it returns that apply() function it creates locally. This is where the partial application happens. The value we get back from table.map() in this case is a function which accepts one argument: a table, which it proceeds to process in the same way as the two-parameter form of table.map(). For example:


local function triple(x) return x * 3 end

local y = table.map(triple) { 100, 200, 300 }
local printEach = table.map(print)

printEach(y)

Our use of table.map(print) is a clear example of partial application. What we get in return is a function, printEach() in this example, which we can latter call with any table as its argument to get the same results we’d get from calling table.map(print, values) in the first place. This is a nice abstraction for defining functions that perform some operating for every element in a table.

The other example of partial application in the code above demonstrates a combination of one of Lua’s syntax shortcuts: if a function accepts only one argument and that argument is a string or table then the parentheses for the function call are optional. This is why we can write:

local y = table.map(triple) { 100, 200, 300 }

First table.map(triple) returns a function of one argument, and then we immediately call that function with a table as its argument. In that scenario Lua let’s us drop the parentheses. This concept of a function returning a function combined with Lua’s shortcut regarding parameters provides a way to create some constructs that could be useful as part of a domain-specific language (DSL). Here’s a hypothetical example:


local sql = database.connect("/tmp/db.sqlite") [[
    CREATE TABLE users (id, name);
]]

sql [[ INSERT INTO users (id, name)
       VALUES (1, "Eric"),
              (2, "Jeff"); ]]

-- Because let's waste everyone's time...
sql [[ DROP TABLE users; ]]

Again, there’s nothing clever or fancy going on here. This is merely the kind of construct that can occasionally be useful in a DSL, or a library, or framework, et cetera.

Summary

We can use partial application in Lua by writing functions which, when given fewer than the normal amount of parameters expected, returns a function we can later call on the remaining parameters. In effect we “freeze” the values of the initial parameters. Combined with Lua’s shortcuts for functions of one argument this can be useful for building specialized constructs to simplify our code.

Advertisements

Add Your Thoughts

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s