Lua 函数式编程/函数
在 Lua 中,与 Lisp 一样,函数是一种数据类型;您可以将它们分配给变量并在代码中传递它们。
函数可以用“普通”的方式定义,我们也可以调用它们。
> function double(x) return x*2 end
> return double(1)
2
我们可以通过简单地使用其名称(不带括号)来访问创建的函数对象。因此,我们可以将函数作为参数传递,将其存储在数据结构中,等等。
> return double
function: 0x806a5e8
> a = {double} -- creates an array
> return double == a[1]
true
Lua 中也可以创建所谓的 lambda 表达式或匿名内联函数。它们在几乎所有方面都类似于上面描述的“普通”函数。
> return function(x) return x*2 end
function: 0x806b950
> return (function(x) return x*2 end)(1)
2
请注意,与 Lisp(以及大多数其他语言)不同,函数和其他变量在 Lua 中共享同一个命名空间。事实上,在 Lua 中,函数只是另一种可以存储在变量中的数据。
函数对象可以作为参数传递给其他函数。要将参数作为函数调用,只需在后面附加您想要调用的参数列表即可。使用前面定义的 `double` 函数,我们可以执行以下操作
> function dofunction(f) return f(21) end
> return dofunction(double)
42
接受另一个函数作为参数的“典型”函数示例是 `map`。不幸的是,`map` 不包含在 Lua 中,因此我们必须自己编写代码。
function map(func, array)
local new_array = {}
for i,v in ipairs(array) do
new_array[i] = func(v)
end
return new_array
end
这是一个简单的 `map` 实现,它只适用于一个数组。但它效果很好
> return table.concat(map(double, {1,2,3}),",")
2,4,6
一个更复杂的 `map` 实现,它适用于多个数组是可能的
function mapn(func, ...)
local new_array = {}
local i=1
local arg_length = table.getn(arg)
while true do
local arg_list = map(function(arr) return arr[i] end, arg)
if table.getn(arg_list) < arg_length then return new_array end
new_array[i] = func(unpack(arg_list))
i = i+1
end
end
让我们使用它
> t = mapn(function(a,b) return a+b end, {1,2,3}, {4,5,6})
> return table.concat(t,",")
5,7,9
排序是内置的,但是,如果需要,我们可以传递一个排序函数。
> t = {1,4,2,5,6,7,3}
> table.sort(t, function(a,b) return a<b end)
> return table.concat(t,",")
1,2,3,4,5,6,7
On Lisp 提供了 Lisp 中 `remove-if` 实现的示例。`remove-if` 不是 Lua 的内置函数,因此我们不妨编写一个等效于下面 Lisp 代码的 Lua 实现。
function cdr(arr)
local new_array = {}
for i = 2, table.getn(arr) do
table.insert(new_array, arr[i])
end
return new_array
end
function cons(car, cdr)
local new_array = {car}
for _,v in cdr do
table.insert(new_array, v)
end
return new_array
end
function lisp_remove_if(func, arr)
if table.getn(arr) == 0 then return {} end
if func(arr[1]) then
return lisp_remove_if(func, cdr(arr))
else
return cons(arr[1], lisp_remove_if(func, cdr(arr)))
end
end
与以下 Lisp 代码比较
(defun our-remove-if (fn lst)
(if (null lst)
nil
(if (funcall fn (car lst))
(our-remove-if fn (cdr lst))
(cons (car lst) (our-remove-if fn (cdr lst))))))
上面的 Lua 和 Lisp 代码都是尾递归安全的(见下面的尾递归)。(两种语言的大多数实现都支持尾递归优化。)仅供比较,以下是我会编写“纯”Lua 版本的方式
function lua_remove_if(func, arr)
local new_array = {}
for _,v in arr do
if not func(v) then table.insert(new_array, v) end
end
return new_array
end
在 Lua 中,我们必须定义辅助函数 `cdr` 和 `cons`,它们是 Lisp 的内置函数,但使用 `remove_if` 非常容易
> t = lisp_remove_if(function(x) return math.mod(x,2)==0 end, {1,2,3,4,5})
> return table.concat(t,",")
1,3,5