《Lua程序设计(第2版)》 6.3 正确的尾调用(proper tail call)

  Lua是支持尾调用消除(tail-call elimination)的,如下面对函数g的调用就是尾调用。

 function f(x) return g(x) end

  尾调用之后,程序不需要保存任何关于函数f的栈(stack)信息,即不耗费任何栈空间。

  尾调用方法可用于编写状态机(state machine),类似于goto到另一个函数,如果没有尾调用消除,每次调用都会创建一个新的栈层(stack level),若干步之后有可能导致栈溢出。

  注意,以下几种情况均不是尾调用:

 function f(x)
g(x)
end return g(x) +
return x or g(x)
return (g(x))

  举例,书中有个迷宫的例子,代码如下:

入口

room1

room2
room3

出口

room4

  

 function room1 ()
local direction = io.read()
if direction == "east" then
room2()
elseif direction == "south" then
room3()
else
print("invalid direction!")
room1()
end
end function room2 ()
local direction = io.read()
if direction == "west" then
return room1()
elseif direction == "south" then
return room4()
else
print("invalid direction!")
return room2()
end
end function room3 ()
local direction = io.read()
if direction == "north" then
return room1()
elseif direction == "east" then
return room4()
else
print("invalid direction!")
return room3()
end end function room4 ()
print("congratulations!")
end room1()

运行结果:

south
west
invalid direction!
east
congratulations!

我们写一个尾调用的简单循环:

 function room1()
return room2()
end function room2()
print()
return room1()
end room1()

运行结果:

 -- 一直循环不会报错

不使用尾调用:

 function room1()
room2()
end function room2()
print()
room1()
end room1()

运行结果:

 -- 循环几秒之后出现以下报错:

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

[Lua] 尾调用消除(tail-call elimination)的更多相关文章

  1. Lua 正确的尾调用(proper tail call)

    Lua支持“尾调用消除(tail-call elimination)”.尾调用(tail call):当一个函数调用是另一个函数的最后一个动作时,该调用才算是一条“尾调用”.例如,下面的代码就是一条“ ...

  2. PHP、Lua中的 尾调用

    在程序设计中,递归(Recursion)是一个很常见的概念,合理使用递归,可以提升代码的可读性,但同时也可能会带来一些问题. 下面以阶乘(Factorial)为例来说明一下递归的用法,实现语言是PHP ...

  3. JavaScript中的尾调用优化

    文章来源自:http://www.zhufengpeixun.com/qianduanjishuziliao/javaScriptzhuanti/2017-08-08/768.html JavaScr ...

  4. ES6躬行记(15)——箭头函数和尾调用优化

    一.箭头函数 箭头函数(Arrow Function)是ES6提供的一个很实用的新功能,与普通函数相比,不但在语法上更为简洁,而且在使用时也有更多注意点,下面列出了其中的三点: (1)由于不能作为构造 ...

  5. ES6学习笔记 -- 尾调用优化

    什么是尾调用? 尾调用(Tail Call)是函数式编程的一个重要概念,就是指某个函数的最后一步是调用另一个函数. function f(x) { return g(x) } 如上,函数 f 的最后一 ...

  6. iOS 的尾调用优化原理

    背景: 今天聊代码规范的问题的时候说了一下尾调用的问题. 一:概念: 什么是尾调用? 尾调用(Tail Call):某个函数的最后一步仅仅只是调用了一个函数(可以是自身,可以是另一个函数). 注意 “ ...

  7. lua报错,看到报错信息有tail call,以为和尾调用有关,于是查了一下相关知识

    尾调用是指在函数return时直接将被调函数的返回值作为调用函数的返回值返回,尾调用在很多语言中都可以被编译器优化, 基本都是直接复用旧的执行栈, 不用再创建新的栈帧, 原理上其实也很简单, 因为尾调 ...

  8. JavaScript 中的尾调用

    尾调用(Tail Call) 尾调用是函数式编程里比较重要的一个概念,它的意思是在函数的执行过程中,如果最后一个动作是一个函数的调用,即这个调用的返回值被当前函数直接返回,则称为尾调用,如下所示: f ...

  9. lua如何调用C++函数

    第一步是定义函数.所有在Lua中被调用的C/C++函数将使用下面一类指针进行调用: typedef int (*lua_CFunction) (lua_State *L); 换句话说,函数必须要以Lu ...

随机推荐

  1. Promise & Deferred objects in JavaScript Pt.1: Theory and Semantics.

    原文:http://blog.mediumequalsmessage.com/promise-deferred-objects-in-javascript-pt1-theory-and-semanti ...

  2. 【问题定位】tcpdump 抓包简易命令

    tcpdump -A -i lo port 2003 or port 2103 or port 2203 | grep '.*system.*'

  3. JS相关知识点总结

    一.获取元素方法 1.document.getElementById("元素id号"); 可以使用内置对象document上的getElementById方法来获取页面上设置了id ...

  4. 1692. [USACO07DEC] 队列变换【后缀数组+贪心】

    Description FJ打算带他的N(1 <= N <= 30,000)头奶牛去参加一年一度的“全美农场主大奖赛”.在这场比赛中,每个参赛者都必须让他的奶牛排成一列,然后领她们从裁判席 ...

  5. 安卓预览报错 Failed to load AppCompat ActionBar with unknown error

    报错信息 : Render ProblemFailed to load AppCompat ActionBar with unknown error. Failed to instantiate on ...

  6. ethers.js-4-Contracts

    Contracts A Contract is an abstraction of an executable program on the Ethereum Blockchain. A Contra ...

  7. Python自动化之django orm之Q对象

    Python自动化之django orm之Q对象 什么是Q对象? Encapsulates filters as objects that can then be combined logically ...

  8. YUV与RBG的装换公式

    Y’ = 0.257*R' + 0.504*G' + 0.098*B' + 16 Cb Cr R) G) - 0.392*(Cb'-128) B)

  9. Spring源码分析(二十三)BeanFactory的后处理

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.激活注册的 BeanFactoryPostProcessor ...

  10. P2280 [HNOI2003]激光炸弹

    题目描述 输入输出格式 输入格式: 输入文件名为input.txt 输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示 xi,yi ,vi . 输出格式: 输出文件名为out ...