This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.
Programming in Lua | ||
Part I. The Language Chapter 6. More about Functions |
Functions in Lua are first-class values with proper lexical scoping.
What does it mean for functions to be "first-class values"? It means that, in Lua, a function is a value with the same rights as conventional values like numbers and strings. Functions can be stored in variables (both global and local) and in tables, can be passed as arguments, and can be returned by other functions.
What does it mean for functions to have "lexical scoping"? It means that functions can access variables of its enclosing functions. (It also means that Lua contains the lambda calculus properly.) As we will see in this chapter, this apparently innocuous property brings great power to the language, because it allows us to apply in Lua many powerful programming techniques from the functional-language world. Even if you have no interest at all in functional programming, it is worth learning a little about how to explore those techniques, because they can make your programs smaller and simpler.
A somewhat difficult notion in Lua is that functions,
like all other values, are anonymous;
they do not have names.
When we talk about a function name, say print
,
we are actually talking about a variable that holds that function.
Like any other variable holding any other value,
we can manipulate such variables in many ways.
The following example, although a little silly,
shows the point:
a = {p = print} a.p("Hello World") --> Hello World print = math.sin -- `print' now refers to the sine function a.p(print(1)) --> 0.841470 sin = a.p -- `sin' now refers to the print function sin(10, 20) --> 10 20Later we will see more useful applications for this facility.
If functions are values, are there any expressions that create functions? Yes. In fact, the usual way to write a function in Lua, like
function foo (x) return 2*x endis just an instance of what we call syntactic sugar; in other words, it is just a pretty way to write
foo = function (x) return 2*x endThat is, a function definition is in fact a statement (an assignment, more specifically) that assigns a value of type
"function"
to a variable.
We can see the expression function (x) ... end
as a function constructor,
just as {}
is a table constructor.
We call the result of such function constructors an
anonymous function.
Although we usually assign functions to global names,
giving them something like a name,
there are several occasions when functions remain anonymous.
Let us see some examples.
The table library provides a function table.sort
,
which receives a table and sorts its elements.
Such a function must allow unlimited variations in the sort order:
ascending or descending, numeric or alphabetical,
tables sorted by a key, and so on.
Instead of trying to provide all kinds of options,
sort
provides a single optional parameter,
which is the order function:
a function that receives two elements
and returns whether the first must come before
the second in the sort.
For instance, suppose we have a table of records such as
network = { {name = "grauna", IP = "210.26.30.34"}, {name = "arraial", IP = "210.26.30.23"}, {name = "lua", IP = "210.26.23.12"}, {name = "derain", IP = "210.26.23.20"}, }If we want to sort the table by the field
name
,
in reverse alphabetical order,
we just write
table.sort(network, function (a,b) return (a.name > b.name) end)See how handy the anonymous function is in that statement.
A function that gets another function as an argument,
such as sort
,
is what we call a higher-order function.
Higher-order functions are a powerful programming mechanism
and the use of anonymous functions
to create their function arguments is a great source of flexibility.
But remember that
higher-order functions have no special rights;
they are a simple consequence of the ability of Lua to handle
functions as first-class values.
To illustrate the use of functions as arguments,
we will write a naive implementation of
a common higher-order function,
plot
, that plots a mathematical function.
Below we show this implementation,
using some escape sequences to draw on an ANSI terminal.
(You may need to change these control sequences
to adapt this code to your terminal type.)
function eraseTerminal () io.write("\27[2J") end
-- writes an `*' at column `x' , row `y' function mark (x,y) io.write(string.format("\27[%d;%dH*", y, x)) end
-- Terminal size TermSize = {w = 80, h = 24} -- plot a function -- (assume that domain and image are in the range [-1,1]) function plot (f) eraseTerminal() for i=1,TermSize.w do local x = (i/TermSize.w)*2 - 1 local y = (f(x) + 1)/2 * TermSize.h mark(i, y) end io.read() -- wait before spoiling the screen endWith that definition in place, you can plot the sine function with a call like
plot(function (x) return math.sin(x*2*math.pi) end)(We need to massage the data a little to put values in the proper range.) When we call
plot
,
its parameter f
gets the value of
the given anonymous function,
which is then called inside the for loop repeatedly
to provide the values for the plotting.
Because functions are first-class values in Lua, we can store them not only in global variables, but also in local variables and in table fields. As we will see later, the use of functions in table fields is a key ingredient for some advanced uses of Lua, such as packages and object-oriented programming.
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. |