[Lua] 尾調用消除(tail-call elimination)


《Lua程序設計(第2版)》 6.3 正確的尾調用(proper tail call)

  Lua是支持尾調用消除(tail-call elimination)的,如下面對函數g的調用就是尾調用。

1 function f(x) return g(x) end

  尾調用之后,程序不需要保存任何關於函數f的棧(stack)信息,即不耗費任何棧空間。

  尾調用方法可用於編寫狀態機(state machine),類似於goto到另一個函數,如果沒有尾調用消除,每次調用都會創建一個新的棧層(stack level),若干步之后有可能導致棧溢出。

  注意,以下幾種情況均不是尾調用:

1 function f(x)
2     g(x)
3 end
4 
5 return g(x) + 1
6 return x or g(x)
7 return (g(x))

 

  舉例,書中有個迷宮的例子,代碼如下:

入口

room1

room2
room3

出口

room4

  

 1 function room1 ()
 2     local direction = io.read()
 3     if direction == "east" then
 4         room2()
 5     elseif direction == "south" then
 6         room3()
 7     else
 8         print("invalid direction!")
 9         room1()
10     end
11 end
12 
13 function room2 ()
14     local direction = io.read()
15     if direction == "west" then
16         return room1()
17     elseif direction == "south" then
18         return room4()
19     else
20         print("invalid direction!")
21         return room2()
22     end
23 end
24 
25 function room3 ()
26     local direction = io.read()
27     if direction == "north" then
28         return room1()
29     elseif direction == "east" then
30         return room4()
31     else
32         print("invalid direction!")
33         return room3()
34     end
35 
36 end
37 
38 function room4 ()
39     print("congratulations!")
40 end
41 
42 room1()

運行結果:

south
west
invalid direction!
east
congratulations!

 

我們寫一個尾調用的簡單循環:

 1 function room1()
 2     return room2()
 3 end
 4 
 5 function room2()
 6     print(111)
 7     return room1()
 8 end
 9 
10 room1()

運行結果:

111
111 -- 一直循環不會報錯

 

不使用尾調用:

 1 function room1()
 2     room2()
 3 end
 4 
 5 function room2()
 6     print(111)
 7     room1()
 8 end
 9 
10 room1()

運行結果:

111
111 -- 循環幾秒之后出現以下報錯:

lua: stack overflow
stack traceback:
        [C]: in function 'print'
        6_propertailcall.lua:47: in function 'room2'
        6_propertailcall.lua:43: in function 'room1'
        6_propertailcall.lua:48: in function 'room2'
        6_propertailcall.lua:43: in function 'room1'
        6_propertailcall.lua:48: in function 'room2'
        6_propertailcall.lua:43: in function 'room1'
        6_propertailcall.lua:48: in function 'room2'
        6_propertailcall.lua:43: in function 'room1'
        6_propertailcall.lua:48: in function 'room2'
        ...
        6_propertailcall.lua:48: in function 'room2'
        6_propertailcall.lua:43: in function 'room1'
        6_propertailcall.lua:48: in function 'room2'
        6_propertailcall.lua:43: in function 'room1'
        6_propertailcall.lua:48: in function 'room2'
        6_propertailcall.lua:43: in function 'room1'
        6_propertailcall.lua:48: in function 'room2'
        6_propertailcall.lua:43: in function 'room1'
        6_propertailcall.lua:51: in main chunk
        [C]: ?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM