极致之美——百行代码实现全新智能语言Lisp(3)
作者:月影 来源:51js 发布时间:2010-07-13 13:07:00
接着我们定义一个记号来描述函数.函数表示为[lambda, [...], e],其中 ...是原子(叫做参数),e是表达式. 如果表达式的第一个元素形式如上
[[lambda,[...],e],...]
则称为函数调用.它的值计算如下.每一个表达式先求值,然后e再求值.在e的求值过程中,每个出现在e中的的值是相应的在最近一次的函数调用中的值.
> [[lambda,['x'],[cons,'x',[_,[c]]]],[_,a]]
[a,c]
> [[lambda,['x','y'],[cons,'x',[cdr,'y']]],[_,z],[_,[a,b,c]]]
[z,b,c]
lambda = function(args, code)
{
if(code instanceof Array)
{
var fun = new Function(args,
"for(var i = 0; i < arguments.length; i++) arguments[i] = LispScript.Run(arguments[i]);return LispScript.Run("+code.toEvalString()+");");
var globalFuncName = __funList.pop();
fun._funName = globalFuncName;
if(globalFuncName != null)
self[globalFuncName] = fun;
return fun;
}
return [];
};
如果一个表达式的第一个元素f是原子且f不是原始操作符
[f ...]
并且f的值是一个函数[lambda,[...]],则以上表达式的值就是
[[lambda,[...],e],...]
的值. 换句话说,参数在表达式中不但可以作为自变量也可以作为操作符使用:
> [[lambda,[f],[f,[_,[b,c]]],[_,[lambda,[x],[cons,[_,a],x]]]
[a,b,c]
有另外一个函数记号使得函数能提及它本身,这样我们就能方便地定义递归函数.记号
[label,f,[lambda,[...],e]]
表示一个象[lambda,[...],e]那样的函数,加上这样的特性: 任何出现在e中的f将求值为此label表达式, 就好象f是此函数的参数.
假设我们要定义函数[subst,x,y,z], 它取表达式x,原子y和表z做参数,返回一个象z那样的表, 不过z中出现的y(在任何嵌套层次上)被x代替.
> [subst,[_,m],[_,b],[_,[a,b,[a,b,c],d]]]
[a,m,[a,m,c],d]
我们可以这样表示此函数
[label,subst,[lambda,[x,y,z],
[cond,[[atom,z],
[cond,[[eq,z,y],x],
true,z]]],
[true,[cons,[subst,x,y,[car,z]],
[subst,x,y,[cdr,z]]]]]]]
label = function(funName, funDef)
{
__funList.push(funName);
return LispScript.Run(funDef);
};
我们简记f=[label,f,[lambda,[...],e]]为
[defun,f,[...],e]
defun = function(funName, args, code)
{
__funList.push(funName);
if(code instanceof Array)
{
var fun = new Function(args,
"for(var i = 0; i < arguments.length; i++) arguments[i] = LispScript.Run(arguments[i]);return LispScript.Run("+code.toEvalString()+");");
var globalFuncName = __funList.pop();
fun._funName = globalFuncName;
if(globalFuncName != null)
self[globalFuncName] = fun;
return fun;
}
return [];
};
于是
[defun,subst,[x,y,z],
[cond,[[atom,z],
[cond,[[eq,z,y],x],
[true,z]]],
[true,[cons,[subst,x,y,[car,z]],
[subst,x,y,[cdr,z]]]]]]
偶然地我们在这儿看到如何写cond表达式的缺省子句. 第一个元素是't的子句总是会成功的. 于是
[cond,[x,y],[[_,true],z]]
等同于我们在某些语言中写的
if x then y else z
对于函数调用,具有如下结构:[FunName,[_,args]]
其中FunName是函数名称,[_,args]是指定参数引用列表args
注意[FunName,args]也是合法的,但是和[FunName,[_,args]]有所区别,对于前者,指令在被调用之前先计算args的值,把计算出的值作为参数列表代入函数计算(期望args计算结果为List),而后者的args参数列表在函数指令调用时才被计算


猜你喜欢
- HTML文件其实就是由一组尖括号构成的标签组织起来的,每一对尖括号形式一个标签,标签之间存在上下关系,形成标签树;XPath 使用路径表达式
- 本文实例讲述了MySQL数据库优化之分表分库操作。分享给大家供大家参考,具体如下:分表分库垂直拆分垂直拆分就是要把表按模块划分到不同数据库表
- 很多时候,我发现自己需要进行生成报告、输出文件或字符串的任务。它们或多或少都会遵循某种模式,通常这些模式是如此相似,以至于我们希望拥有一个可
- 本文介绍基于Python语言,针对一个文件夹下大量的Excel表格文件,基于其中每一个文件的名称,从另一个文件夹中找到与这一文件夹中文件同名
- 一、中间件的基本使用在web开发中,中间件起着很重要的作用。比如,身份验证、权限认证、日志记录等。以下就是各框架对中间件的基本使用。1.1
- 本文实例讲述了Python常用特殊方法。分享给大家供大家参考,具体如下:1 __init__和__new____init__方法用来初始化类
- 本文实例讲述了PHP实现逐行删除文件右侧空格的方法。分享给大家供大家参考,具体如下:在编辑整理代码的过程中发现网上的一些代码经常会有不少的右
- 背景说的事务,大家应该都不陌生,开发用到 MySql 数据库的时候,通常会用到事务。其中比较经典的例子就是转账,比如你要给小明转 50 块钱
- 约定:import pandas as pdimport numpy as npfrom numpy import nan as NaN填充
- Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年
- 在 PHP 中实现异步定时多任务消息推送的方式有多种,其中一种常用的方式是使用异步任务队列。以下是一个简单的步骤:安装和配置消息队列服务(如
- 前言昨天,在本地安装 Swoole 调试环境的时候,遇到好几个坑,因为我的电脑是 Windows 系统,所以安装的是 cygwin ,但是过
- <script> function window.onload(){ if(location.href.indexOf('
- 前言最近不是快过年了,Python写对联挺火的,但是代码又不是人人都用,那就直接写个界面打包一下呗~主要实现只要运行后输入上联下联、横批,然
- 0. 学习目标在顺序存储方式中,根据数据元素的序号就可随机存取表中任何一个元素,但同时在插入和删除运算需要移动大量的元素,造成算法效率较低。
- Taglib指令介绍Taglib指令,其实就是定义一个标签库以及自定义标签的前缀。比如struts中支持的标签库,html标签库、bean标
- 通过一条命令用Npm安装gulp-htmlmin:npm install gulp-htmlmin --save-dev安装完毕后,打开gu
- 目录前言1.insert ignore into2.on duplicate key update3.replace into4.inser
- 本文针对安装mysql5.7.21的笔记进行了总结,分享给大家1、将下载好的mysql压缩包解压到安装目录下2、新建文件 my.ini,放置
- 这篇文章主要介绍了Python如何实现强制数据类型转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋