从例子中学习闭包和范式for

又翻起了programming in lua这本书了,而且又看到 感谢贡献之人这段代码,今天就对这段代码做下分析。代码如下:

-- file: 'thanks.lua'
-- desc: to print the list of the contributing guys
function list_iter (t)
     local i = 0
     local n = table.getn(t)
     return function ()
          i = i + 1
          if i <= n then return t[i] end
     end
end
helpful_guys = {
    "----参与翻译----",
    "buxiu", "凤舞影天", "zhang3",
    "morler", "lambda", "sunlight",
    "\n",
    "----参与校对----",
    "凤舞影天", "doyle", "flicker",
    "花生魔人", "zhang3", "Kasi",
    "\n"
}
for e in list_iter( helpful_guys ) do
     print(e)
end

对于这段代码,我们分两个部分来讲,第一部分是闭包,第二部分是范式for的运行过程.

首先先讲闭包,简单一点说,闭包就是 一个内部函数,它可以访问一个或多个外部函数的外部局部变量
结构:包含两个函数,一个是闭包自己,一个是工厂(创建闭包的函数)

-- 这里list_iter函数是创建闭包的工厂
function list_iter( t )
    local i = 0
    local n = table.getn( t )
    -- 匿名函数,list_iter函数的返回值
    return function ()
        -- 变量i、n和t相对于这个匿名函数,是个外部函数(list_iter)的局部变量
        i = i + 1
        if i <= n then return t[i] end
    end
end

先看下上面的list_iter函数,它的返回值是一个函数,这个函数保存着三个外部的局部变量i,n和t
大家想一下:

fFunc = list_iter( {"a", "b"} )

运行list_iter的返回值就是一个函数, 它保存了三个值,i=0, n=2, t={“a”, “b”}
第一次运行fFunc函数, 即

 print( fFunc() )

输出结果为 a
因为 fFunc 它是一个函数,运行的时候
i=i+1 这时i=0+1=1
t[1] 就是 a

运行完之后,这个fFunc的保存的 外部的局部变量 i变成了1

同理再运行一下 fFunc时,
输出的结果为 b
同时,这个fFunc的保存的 外部的局部变量 i变成了2

这时候再运行一下的时候,结果就是nil, 因为
i=2+1 等于 3
i<=n不成立了(3<=2不成立)

所以接下来运行的时候,结果都是为nil,
但是每运行一次的时候,fFunc这个闭包的局部变量 i就会加1

function iter_list( t )
    local i = 0
    local n = table.getn(t)
    return function()
        i = i + 1
        print( "i=", i )
        if i<= n then
            return t[i]
        end
    end
end
fFunc = iter_list( {"a", "b"} )
print( fFunc() )
print( fFunc() )
print( fFunc() )
print( fFunc() )

运行结果:
这里写图片描述

接下来讲一下范式for的运行过程
其语法如下

for <var-list> in <exp-list> do
    <body>
end

其中
var-list 是一个或多个以逗号分割的变量名列表
exp-list 是一个或多个以逗号分割的表达式列表,迭代函数(闭包),状态常量和控制变量
通常情况下 exp-list 为:迭代工厂的调用。 即: iter_list() 其返回值是一个闭包

其运行过程为:

do
    -- _f为迭代函数,_s为状态常量,_var为控制变量
    local _f, _s, _var = explist
    while true do
        -- 迭代函数的参数有两个
        -- 第一个是状态常量_s, 这个值是explist返回的第二个参数
        -- 第二个是控制常量,第一次的值是explist返回的第三个参数,后面的值是上次运行_f返回的第一个返回值
        local var_1, ... , var_n = _f( _s, _var )
        -- 接下来_f的第二个参数,变成上一次运行_f返回的第一个值
        _var = var_1
        -- 如果控制变量为nil就结束
        if _var == nil then 
            break 
        end
        block
    end
end

上面的解释可能一开始看不懂,没关系,接下来根据实例来说明一下,这里用最开始那个感谢的函数来说明:

function list_iter(t)
    local i = 0
    local n = table.getn(t)
    return function ()
        i = i + 1
        if i <= n then return t[i] end
    end
end
helpful_guys = {
    "----参与翻译----",
    "buxiu", "凤舞影天", "zhang3",
    "morler", "lambda", "sunlight",
    "\n",
    "----参与校对----",
    "凤舞影天", "doyle", "flicker",
    "花生魔人", "zhang3", "Kasi",
    "\n"
}

-- 这里 in 后面的结果,我们希望是一个迭代函数,一个状态常量,一个控制常量
-- 但是这里是 list_iter( helpful_guys )
-- 也就是说 local _f, _s, _var = list_iter( helpful_guys )的返回值
-- 因为list_iter只有一个返回值,所以这里的三个变量分别为
-- _f 为闭包, _s = nil, _var = nil
for e in list_iter( helpful_guys ) do
    -- 第一次运行_f的时候,返回值是helpful_guys的第一个元素;"----参与翻译----"
    -- 根据上面分析for的运行过程,可知,这里就是一直运行_f函数,直到其返回值为nil就就结束
    print(e)
end

上面的

for e in list_iter( helpful_guys ) do
    print( e )
end

等价于

_f, _s, _var = list_iter( helpful_guys )
for e in _f, _s, _var do
    print( e )
end

运行的_f的过程中,其实是有传入状态常量_s,和后续变化的控制变量_var,只是这里闭包函数没有参数而已

我们可以修改一下迭代工厂,就可以看到状态常量_s和控制变量_var

function list_iter( t )
    local i = 0
    local n = table.getn( t )
    -- _s为状态常量,其值是迭代工厂返回的第二个值,这里就是 "我是状态常量"
    -- _var为控制变量,第一次是迭代工厂返回的第三个值,后续是闭包运行返回的第一个值
    return function ( _s, _var )
        print( "状态常量:", _s )
        print( "控制量:", _var )
        i = i + 1
        if i <= n then return t[i] end
    end, "我是状态常量", "我是初始的控制变量"
end

for e in list_iter( {"a"} ) do
    print(e)
end

运行结果:
这里写图片描述

上面就是从例子中学到的闭包和范式for的运行过程,有什么问题,欢迎留言讨论

### 数据库中的闭包概念及其实现方法 #### 什么是数据库闭包? 在数据库理论中,闭包是指由一组属性通过函数依赖推导出的所有可能的属性集合。这一过程基于给定的函数依赖集 \( F \),通过对初始属性逐步应用函数依赖规则来扩展其范围[^1]。 #### 如何计算属性闭包? 假设有一个关系模式 \( R(U, F) \),其中 \( U \) 是属性全集,\( F \) 是定义在其上的函数依赖集。对于任意子集 \( X \subseteq U \),可以通过以下算法计算 \( X^+ \)(即 \( X \) 的闭包): 1. 初始化:令 \( X_0 = X \)。 2. 迭代:如果存在某个函数依赖 \( A \to B \in F \),使得 \( A \subseteq X_i \),则将 \( B \) 添加到当前集合中形成新的集合 \( X_{i+1} \)。 3. 终止条件:当连续两次迭代的结果相等时停止,此时得到的集合就是 \( X^+ \)[^5]。 #### 计算实例 考虑题目提到的关系模式 \( R(A, B, C, D) \) 函数依赖集 \( F=\{D\to B, B\to D, AD\to B, AC\to D\}\),我们尝试求解某属性组合的闭包作为例子说明如何操作。 - **目标**:验证某些特定条件下哪些属性能够被推出。 例如,如果我们想测试 {A,C} 是否能决定整个属性组,则按照上述步骤逐一加入符合条件的新成员直到无法再增加为止。 ```python def compute_closure(attributes, fd_set): closure = set(attributes) while True: updated = False for (left_side, right_side) in fd_set: if set(left_side).issubset(closure): # 如果左侧完全包含于现有closure new_elements = set(right_side) - closure if len(new_elements) > 0: # 发现新元素 closure.update(new_elements) updated = True if not updated: # 若本轮未更新,则结束循环 break return sorted(list(closure)) # 定义输入数据 attributes_to_test = ['A', 'C'] functional_dependencies = [ ('D', 'B'), ('B', 'D'), ('AD', 'B'), ('AC', 'D') ] result = compute_closure(attributes_to_test, functional_dependencies) print(f"Closure of {''.join(attributes_to_test)} is {''.join(result)}.") ``` 此代码片段展示了如何编程模拟手动计算的过程,并得出最终结果用于后续分析如寻找候选键等活动。 #### 关联知识点提醒 需要注意的是,在实际项目开发过程中虽然理论上追求规范化形式比如三范式(Third Normal Form, 3NF)或者修正后的Boyce-Codd 范式(BCNF),但在实践中往往需要综合考量效率等因素做出适当调整。 另外关于程序设计领域内的另一种含义——闭包(Closures),尽管名称相同但两者并无直接联系;前者属于逻辑推理范畴下的数学运算,后者则是高级语言特性之一涉及匿名函数与词法作用域绑定等问题[^2][^3].
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值