《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. 学习博客之Java继承多态接口

    这一篇博客主要是对软工前一阶段学习的总结,主要是对Java的学习总结,包括三部分:Java的继承.多态和接口 Java的继承 继承是面向对象的三大特性之一,能够实现软件的复用. Java子类继承父类的 ...

  2. [MongoDB]------windos远程服务器部署连接

    1.连接前的准备 这里就省略了服务器上安装的操作,跟上一节是一样的流程. 连接到远程服务器,首先需要到远程服务器上在mongoDb安装根目录下的bin文件夹(默认安装目录是C:\Program Fil ...

  3. Linux新建用户没有设置密码

    只要你能登陆root账户就行 登陆root账户 输入  echo "密码“ | passwd --stdin 用户名

  4. Java 实现对文件系统的监控

    在开发中经常会用到监控文件或是目录的状态,如果你还在手写轮巡扫描文件的话,那你久out了. 1. Commons io为我们提供了一套可靠.高性能的一套文件系统监控API 1.1. 需要的jar包如下 ...

  5. 如何运行vue项目(从gethub上download的开源项目)

    前提:入坑vue.js,从GitHub上download一个vue.js的开源项目,发现不知如何在浏览器运行,通过查阅网上教程,发现网上的很多是教你怎么新建项目,并没有一个是教如何打开已有的项目.自已 ...

  6. linux 字体 设置 en_US.UTF-8

    设置:localectl    set-local    LANG=en_US.UTF-8 查看: localectl list-locales

  7. [Java123]软件自动生成接口文档

    需求场景:进入新项目,开始老本行读源码. 急需要快速了解项目的各个接口架构. https://www.jianshu.com/p/4c31e9920537

  8. transfer function

    线性变化后,往往希望进行非线性变化,常用的非线性变化函数有Sigmoid,Tanh,ReLU.会发现,经过这三个函数变化后,Tensor的维度并不发生变化. tanh(双曲正切函数):

  9. mysql root密码忘记重置及相关注意事项

    1.使用mysqld_safe --skip-grant-tables跳过授权,进入mysql操作界面或者在配置文件mysqld 添加skip-grant-tables也行,找回后需要删除..恢复原样 ...

  10. [转]Apache HTTP Server 与 Tomcat 的三种连接方式介绍

    首先我们先介绍一下为什么要让 Apache 与 Tomcat 之间进行连接.事实上 Tomcat 本身已经提供了 HTTP 服务,该服务默认的端口是 8080,装好 tomcat 后通过 8080 端 ...