Skip to content

Latest commit

 

History

History
201 lines (171 loc) · 3.58 KB

1.6.md

File metadata and controls

201 lines (171 loc) · 3.58 KB

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))

closure

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

non-global function

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

proper tail call

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 ()