[Lua] 尾调用消除(tail-call elimination)
《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)的更多相关文章
- Lua 正确的尾调用(proper tail call)
Lua支持“尾调用消除(tail-call elimination)”.尾调用(tail call):当一个函数调用是另一个函数的最后一个动作时,该调用才算是一条“尾调用”.例如,下面的代码就是一条“ ...
- PHP、Lua中的 尾调用
在程序设计中,递归(Recursion)是一个很常见的概念,合理使用递归,可以提升代码的可读性,但同时也可能会带来一些问题. 下面以阶乘(Factorial)为例来说明一下递归的用法,实现语言是PHP ...
- JavaScript中的尾调用优化
文章来源自:http://www.zhufengpeixun.com/qianduanjishuziliao/javaScriptzhuanti/2017-08-08/768.html JavaScr ...
- ES6躬行记(15)——箭头函数和尾调用优化
一.箭头函数 箭头函数(Arrow Function)是ES6提供的一个很实用的新功能,与普通函数相比,不但在语法上更为简洁,而且在使用时也有更多注意点,下面列出了其中的三点: (1)由于不能作为构造 ...
- ES6学习笔记 -- 尾调用优化
什么是尾调用? 尾调用(Tail Call)是函数式编程的一个重要概念,就是指某个函数的最后一步是调用另一个函数. function f(x) { return g(x) } 如上,函数 f 的最后一 ...
- iOS 的尾调用优化原理
背景: 今天聊代码规范的问题的时候说了一下尾调用的问题. 一:概念: 什么是尾调用? 尾调用(Tail Call):某个函数的最后一步仅仅只是调用了一个函数(可以是自身,可以是另一个函数). 注意 “ ...
- lua报错,看到报错信息有tail call,以为和尾调用有关,于是查了一下相关知识
尾调用是指在函数return时直接将被调函数的返回值作为调用函数的返回值返回,尾调用在很多语言中都可以被编译器优化, 基本都是直接复用旧的执行栈, 不用再创建新的栈帧, 原理上其实也很简单, 因为尾调 ...
- JavaScript 中的尾调用
尾调用(Tail Call) 尾调用是函数式编程里比较重要的一个概念,它的意思是在函数的执行过程中,如果最后一个动作是一个函数的调用,即这个调用的返回值被当前函数直接返回,则称为尾调用,如下所示: f ...
- lua如何调用C++函数
第一步是定义函数.所有在Lua中被调用的C/C++函数将使用下面一类指针进行调用: typedef int (*lua_CFunction) (lua_State *L); 换句话说,函数必须要以Lu ...
随机推荐
- UE4中的AI行为树简单介绍
UE4引擎中可以实现简单AI的方式有很多,行为树是其中比较常用也很实用的AI控制方式,在官网的学习文档中也有最简单的目标跟踪AI操作教程,笔者在这里只作简单介绍. AIController->和 ...
- postGresql关键字字段重名
在postGresql中如果关键字和自定义的字段重名 即使使用[ ](中括号)或者 ' '(单引号)都没有用,经本人实验. 如果使用" "(双引号),则可以.
- 整合Yolov3到游戏引擎
这篇其实是前文 CUDA版Grabcut的实现 的后续,和上文一样,先放视频. (博客园好像不支持视频,gif文件太大,视频链接) 在上文用CUDA实现opencv下的grabcut后,当时问题主要是 ...
- 【bzoj 4066】 简单题
题目 显然这就是让我们在二维上数个点 如果没有强制在线就随便做啦,扫描线+主席树应该是最好的选择 但是现在强制在线并且卡了树套树的空间,于是只能上\(kdt\)了 我们还是维护一下每个子树分割出来的矩 ...
- 【洛谷】【线段树】P3353 在你窗外闪耀的星星
[题目描述:] /* 飞逝的的时光不会模糊我对你的记忆.难以相信从我第一次见到你以来已经过去了3年.我仍然还生动地记得,3年前,在美丽的集美中学,从我看到你微笑着走出教室,你将头向后仰,柔和的晚霞照耀 ...
- Redis基本数据类型命令汇总
前言 前阶段写Redis客户端作为学习和了解Redis Protocol,基本上把Strintg,List,Hash,Set,SortedSet五种基础类型的命令都写完了,本篇进行总结,也相当于复 ...
- springboot activiti 整合项目框架源码 shiro 安全框架 druid windows10风格
官网:www.fhadmin.org 此项目为Springboot工作流版本 windows 风格,浏览器访问操作使用,非桌面应用程序. 1.代码生成器: [正反双向](单表.主表.明细表.树形表 ...
- js 设计模式——观察者模式
观察者模式 定义 观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,属于行为型模式的一种,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状 ...
- mac php项目除了首页全飘not found
1.httpd.conf配置文件中加载了mod_rewrite.so模块2.AllowOverride None 将None改为 All DocumentRoot "/Library/Web ...
- C语言中数组定义方式
<1>前言 大家首先来思考一个问题,若是我们想要定义两个变量,求这两个数的平均数,该怎么求呢? 例如:int a = 10,b = 20 int average = (a + b) / 2 ...