lua學習之深刻函數第二篇

深刻函數 2

非全局的函數

  1. 函數是第一類值,函數能夠存儲到全局變量,局部變量,table 字段中
  2. lua 函數庫中的大部分函數存儲到 table 字段中
Lib = {}
Lib.foo = function (x, y)
    return x + y
end
Lib.goo = function (x, y)
    return x - y
end
Lib = {
    foo = function (x, y) return x + y end,
    goo = function (x, y) return x - y end
}
Lib = {}
function Lib.foo(x, y) return x + y end
fucntion Lib.goo(x, y) return x - y end
  1. 將一個函數存儲到一個局部變量中,即爲「局部函數」
  2. 該函數只能在對應的做用域使用,對於「程序包」package 頗有用
  3. lua 將每個程序塊看成一個函數來處理
  4. 在程序塊中聲明的函數就是局部函數,只在該程序塊中可見
  5. 詞法域確保了程序包中的其餘函數能夠使用這些局部函數。
local f = function (<參數列表>)
    <函數體>
end

local g = function (<參數列表>)
    <函數代碼>
    f(實參) -- 能夠調用 f
    <函數代碼>
end

local function f(<參數列表>)
    <函數體>
end

-- 階乘 n! = n * (n - 1) * (n - 2) * ... 1
local fact = function (n) -- 錯誤的遞歸函數定義
    if n == 0 then 
        return 1
    else
        return n * fact(n - 1) -- fact 函數定義未完成,調用的是 fact 全局變量,而不是 fact 函數自己
    end
end
    
-- 正確的遞歸函數定義
local fact
fact = function (n)
    if n == 0 then
        return 1
    else
        return n * fact(n - 1)
    end
end

local function foo(<參數>) <函數體> end
-- Lua 將其展開爲:
local foo
foo = function (<參數>) <函數體> end
-- 正確的函數定義,對於間接遞歸無效
local function fact (n)
    if n == 0 then
        return 1
    else
        return n * fact(n - 1)
    end
end
-- 遞歸就是函數調用函數自己
-- 間接遞歸就是 a 函數調用 b 函數而 b 函數又調用了 a 函數
-- 間接遞歸須要使用明確的前向聲明
local f, g
function g ()
    <函數代碼>
    f()
    <函數代碼>
end

function f() -- 不要加 local 若是加上那麼在函數 g 中引用的就處於未定義狀態,由於 lua 會建立一個全新的局部變量 f
    <函數代碼>
    g()
    <函數代碼>
end

正確的尾調用

  1. 「尾調用」是相似於 goto 的函數調用
  2. 當一個函數調用是另外一個函數的最後一個動做時,該調用就是一條「尾調用」
function f (x)
    <函數代碼>
    return g(x)
end
  1. f 調用完 g 以後就沒有執行其餘代碼了
  2. 在這種狀況下,程序就不須要返回「尾調用」所在的函數了
  3. 在「尾調用」以後,程序無需保存任何關於該函數的棧信息
  4. 當 g 返回時,執行控制權能夠直接返回調用 f 的那個點上
  5. 使得在進行「尾調用」時不耗費任何棧空間
  6. 這種實現稱爲「尾調用消除」
-- 尾調用函數
function foo(n)
    if n > 0 then
        return foo(n - 1)
    end
end
-- 調用完 g 函數後還進行了加法操做,非尾調用
return g(x) + 1 
-- 有 or 操做,必須調整爲一個返回值
retrun x or g(x) 
-- 函數外嵌套一個括號,強制其只返回一個返回值
return (g(x))
-- 尾調用標準格式
return <func>(<args>)
-- 是一個尾調用
-- 調用前會對 <func> 及其參數求值
return x[i].foo(x[j] + a * b, i + j)

編寫狀態機

  1. 典型例子:迷宮
-- 四間房間的迷宮
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
  1. 若沒有「尾調用消除」,每次用戶移動都會建立一個新的棧層,若干步後可能會棧溢出
  2. 「尾調用消除」多用戶移動的次數沒有任何限制
  3. 由於每次移動實際上只是完成一條 goto 語句到另外一個函數
相關文章
相關標籤/搜索