函数式编程思想


目前很多程序语言都专注于帮你编写成千上万行的代码,所以此类型的语言所提供的包、命名空间、复杂的类型系统及无数的结构,有上千页的文档需要开发者学习。而函数式编程语言并不帮你编写大量的代码的程序,相反的,仅让你用少量的代码解决关键问题;函数式编程其特性非常适合于大数据处理、科学计算等场景,随着人工智能、机器学习的流行正在变得重要起来;这儿用lua来作为例子讲解,因为nginx实在是太重要了,nginx的编程框架openresty 就是用lua作为语言。对于真正的开发高手是务必要掌握的。

>函数是一种基本类型

这样函数就可以放到变量里面,再进行调用,这儿举一个场景:链式执行一系列函数,例子:

local function f1(x)
    return "[f1" .. x .. "]"
end

local function f2(x)
    return "[f2" .. x .. "]"
end

local function f3(x)
    return "[f3" .. x .. "]"
end
--用循环实现
local function streamFun(tbf,z)
    for _,f in pairs({f1,f2,f3}) do
        z = f(z)
    end
    return z
end
ngx.say("链式执行(循环):",streamFun({f1,f2,f3},"t"))

--//用递归实现
--辅助函数first
local function first(tb)
    tb = tb or {}
    return tb[1]
end
--辅助函数rest
local function rest(tb)
    tb = tb or {}
    local tmp = {}
    for i,v in ipairs(tb) do
        if i>1 then
            table.insert(tmp,v)
        end
    end
    return tmp
end
--线性递归
local function chainFun(tbf,z)
    if 1 == table.getn(tbf) then
        return first(tbf)(z)
    else
        return first(tbf)( chainFun(rest(tbf),z) )
    end
end

ngx.say("链式执行(递归):",streamFun({f1,f2,f3},"t"))

执行结果

链式执行(循环):[f3[f2[f1t]]]
链式执行(递归):[f1[f2[f3t]]]

>函数式有多个返回值

这个功能因为函数可以作为变量,函数的参数又是一个表,怎样去执行这个变量中的函数啦?这儿就需要有这个功能。当然如果语言支持 宏 的话,也可以用宏来实现。例子如下,这个例子只是为了说明这个的实现原理,实际开发中直接用unpack就可以了:

local function first(tb)
    tb = tb or {}
    return tb[1]
end

local function rest(tb)
    tb = tb or {}
    
    local tmp = {}
    for i,v in ipairs(tb) do
        if i>1 then
            table.insert(tmp,v)
        end
    end
    
    return tmp
end

--ngx.say(first({11,22,33,44}))
--ngx.say(rest({11,22,33,44}))

--//这个myUnPark就是吧表里面的元素作为函数的多个返回值返回,
--//实际开发中直接使用预定义的unpack函数,是用C语言实现的
local function myUnPark(tb)
    if 1 == table.getn(tb) then
        return first(tb)
    else
        return first(tb), myUnPark(rest(tb))
    end
end

--ngx.say(myUnPark({1,2,3,4,5}))

local function add4(a,b,c,d) 
    return a + b + c + d
end

local tbags = {1,2,3,4}

ngx.say(add4(myUnPark(tbags)))

执行结果

10

>函数作为另一个函数的参数,高阶函数

这个显而易见的了,因为函数本身就是可以作为变量是第一类型,当然就可以作为参数了

local 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"},
}
--如果我们想通过表的name域排序:
table.sort(network, function (a,b)
    return (a.name > b.name)
end)

local cjson = require("cjson")
ngx.say(cjson.encode(network))

执行结果

[{"IP":"210.26.23.12","name":"lua"},{"IP":"210.26.30.34","name":"grauna"},{"IP":"210.26.23.20","name":"derain"},{"IP":"210.26.30.23","name":"arraial"}]

>函数的返回值是一个函数,就是闭包、柯里化、延迟执行。

函数可以返回一个函数,并且带有哪个函数所在的变量环境,这个就是闭包,一个应用场景就是工作流中的顺序步骤以及分支处理上,还有就是延迟执行,举个例子:

--//闭包、柯里化的例子---
local function zha(x,cnt) 
    local zharlt = "[炸" .. x .. "]";
    local zhacnt = cnt - 1;
    
    return function(y,ct)
        if(zhacnt >= ct) then
            zhacnt = zhacnt - ct;
            return "炒" .. zharlt .."加" .. y ..",还剩" .. zhacnt;
        else
            return "不够了!"
        end 
    end
    
end

--上一个函数返回的函数
local zhafun = zha("鱼",100)

--调用函数后,炸鱼的数量在变少。
ngx.say(zhafun("辣椒",12))
ngx.say(zhafun("大葱",15))

--延迟执行的例子
local function delay(fun,args)
    return function()
        return fun(unpack(args))
    end
end

local delayfun = delay(zhafun,{"蒜苗",11});
ngx.say(delayfun());

执行结果

炒[炸鱼]加辣椒,还剩87
炒[炸鱼]加大葱,还剩72
炒[炸鱼]加蒜苗,还剩61

>对面向对象的支持

函数式编程完全兼容面向对象,非常简单的就实现了面向对象的那些特征,举个例子:

--这个是父类
local _M = {c=3}
function _M:func1(x)
    return (self.a or 0) + x + (self.c or 0) + (self.d or 0)
end

--这儿的new方法同时完成子类和对象的创建
function _M.new(self,tb)
    return setmetatable(tb,{ __index = self })
end

--这儿的c=5 就覆盖了_M的 原先的c=3,
--[[setmetatable(tb,{ __index = self }) 的意思就是说,
如果当前表找到就用当前表,万一找不到这个元素才到元表去找,
这就是继承里面的子类覆盖父类的成员]]
local mb = _M:new({a=3,b=2,c=5,func2 = function(self,x) y=2; return x + y+3 + (self.a or 0) ; end })
--//冒号表示参数里面自动带入self
ngx.say(mb:func1(2)) --执行父类的方法
ngx.say(mb:func2(2)) --执行子类的方法

执行结果

10
12

总结

看到威力了吧,是不是原先要一大堆代码才能实现的,现在几句代码就搞定,而且更接近与人的思维方式。

你可能感兴趣的:(函数式编程思想)