In lua, functions are first-class value, which have a specific lexical scoping.
a = { p = print }
a.p ("Hello") --> Hello
print = math.sin
a.p (print (1)) --> 0.84
the common way to write a function is actually a syntactic sugar
-- syntactic sugar
function foo (x) return 2*x end
-- actual form
foo = function (x) return 2*x end
lua functions are all anonymous functions.
example of advanced function usage
network = {
{ name = "x", ip = "1.1.1.1" },
{ name = ..., ip = ...}
}
table.sort (network, function (a,b) return (a.name > b.name) end)
another example for advanced function usage
function derivative (f, delta)
delta = delta or 1e-4
return function (x)
return (f(x+delta) - f(x))/delta
end
end
c = derivative (math.sin)
print (math.cos(10), c(10))
function sortbygrade (names, grades)
table.sort (names, function (n1, n2) return grades[n1] > grades[n2] end)
--> in the anonymous function "grades" is neither global variable
--> nor local variable, it's named "non-local" variable.
end
function newCounter ()
local i = 0
return function ()
i = i + 1
end
end
c1 = newCounter ()
print (c1()) --> 1
print (c1()) --> 2
Technically speaking, what is a value in Lua is the closure, not the function. The function itself is just a prototype for closures.
--> method 1
oldsin = math.sin
math.sin = function (x) return oldsin (x*math.pi/180) end --> not using angle but rad
--> method 2, sandboxing
do
local oldSin = math.sin
math.sin = function (x) return (oldSin(x*math.pi/180)) end
end
--> then the old sin() can only be accessed by the new sin()
another example
do
local oldOpen = io.open
local access_OK = function (filename, mode)
<CHECK MODE>
end
io.open = function (filename, mode)
if access_OK (filename, mode) then
return oldOpen (filename, mode)
else
return nil, "Access denied."
end
end
end
Lib = {}
Lib.foo = function (...) return ... end
Lib.bar = function (...) return ... end
or using contructor
Lib = {
foo = function (...) return ... end
bar = function (...) return ... end
}
or
Lib = {}
function Lib.foo (...) return ... end
function Lib.bar (...) return ... end
local f = function (...) return ... end
local function f (...) return ... end
it is better to define recursive functions like this
local function fact (n)
if n == 0 then
return 1
else
return n * fact (n-1)
end
end
tail call e.g. the g()
in function f(x) return g(x) end
.
tail call saves stack space. hence a lua program can nest a huge amount of tail calls, e.g. in terms of the following program, any big number won't cause stack overflow.
function foo(n)
if n>0 then return foo(n-1) end
end
Tail call can be used to write state machines. e.g. a maze of 4 rooms
--[[ room layout
+---+---+
| 1 | 2 |
+---+---+
| 3 | 4 |
+---+---+
start : 1
end : 4
]]--
function room1 ()
local move = io.read()
if move == "south" then return room3()
elseif move == "east" then return room2()
else
print ("invalid move")
return room1 ()
end
end
function room2 ()
local move = io.read()
if move == "south" then return room4()
elseif move == "west" then return room1()
else
print ("invalid move")
return room2()
end
end
function room3 ()
local move = io.read()
if move == "north" then return room1()
elseif move == "east" then return room4()
else
print ("invalid move")
return room3()
end
end
function room4 ()
print ("congratulations!")
end
function main ()
room1 ()
end
main ()