极致之美——百行代码实现全新智能语言Lisp(6)
作者:月影 来源:51js 发布时间:2010-07-13 13:07:00
其他(略为复杂)的扩展:
下面我们定义变量的赋值操作[setq,paraName,paraValue]
LispScript.Run(
[defun,'setq',['para','val'],
[ret,[defun,'para',[],[_eval,'val']]]]
);
增加逻辑操作符or,[or,x,y]返回t如果它的自变量有一个为t,否则返回[]
LispScript.Run(
[defun,'or',['x','y'],
[not,[and,[not,'x'],[not,'y']]]]
);
增加循环控制foreach,[foreach,v,[paralist],[expr]]
foreach期望list是一个表,依次取表中的每一个原子作为expr的参数进行计算,返回计算结果的表
LispScript.Run(
[defun,'foreach',['v','list','expr'],
[cond,
[[isNull,'list'],[]],
[true,[cons,[_eval,[_,'expr'],[['v',[car,'list']]]],['foreach','v',[cdr,'list'],[_,'expr']]]]
]
]
);
增加批量赋值操作let,[let,[[a1,v1],[a2,v2]...]]
LispScript.Run(
[defun,'let',['paralist'],
[foreach,"'v'",'paralist',[_,[setq,[car,"'v'"],[car,[cdr,"'v'"]]]]]
]
);
总结
现在该回过头来看看我们究竟做了什么,以及这么做有什么意义了。
首先我们用javascript实现了一个简单的向下递归的词法分析器,它能对嵌套数组的每个原子进行简单处理,加上几个辅助函数(toEvalString(),Assert(),Element()和一个存放函数名称的堆栈...简单来说我们仅用了数十行代码实现了一种全新的“函数式”语言??LispScript的完整内核。
接着我们定义了7种原始操作,它们分别是quote,atom,eq,car,cdr,cons和cond
然后(相对较复杂地),我们定义了三种用来描述和调用函数的标记,它们分别是lambda, label以及defun,于是我们成功地用另外不到百行代码实现了LispScript语言的核心环境。
接着(接下来的部分已经可以完全独立于javascript)我们用7种原始操作符和函数定义标记defun定义出一些新的函数,分别是:isNull,and,not,append,pair,assoc,ret和str
然后我们惊喜地发现,可以仅用一行LispScript指令定义出自身的“解析器”??_eval函数
最后我们在此基础上定义出一些略为复杂的函数,它们包括:or,setq,foreach和let,其中一些新函数带给我们的新语言定义变量和处理循环的能力,加上前面实现的一些函数,一个比较完善的基础环境就搭建成了。
写在最后:LispScript和Lisp
事实上我们依照[ref. Paul Graham.]的精彩描述用javascript实现了LispScript,毫无疑问,它是一种Lisp(或者Lisp风格的函数式语言),尽管功能上还十分简陋,但它确实是符合Lisp的基本思想和拥有Lisp的基本特性。由于javascript数组文法的特点,我用[]取代了[ref. Paul Graham]中的(),用逗号取代了空格作为分隔符。同[ref. Paul Graham]的文章以及目前一些标准(或者相对标准)的Lisp不同的是,我根据javascript灵活的特点有意弱化了LispScript的语法结构,这样使得LispScript更加灵活,也更加方便实现,然而代价是一小部分的可维护性和安全性。
最后,LispScript还有许多需要完善的内容,例如,最明显地是它基本上还不具有基本的数值运算能力(相对而言,符号操作能力已经比较完善),另外对原子操作参数合法性的检验、副作用, 连续执行 (它得和副作用在一起才有用), 动态可视域、复杂数据结构支持以及注释文法(这相当重要!)也都是它所欠缺的,不过这些功能“都可以令人惊讶地用极少的额外代码来补救”。
感谢约翰麦卡锡,这位天才早在数十年前就向我们展示了一种程序设计领域内至今无人能超越的“极致的美”,他于1960年发表了一篇非凡的论文,他在这篇论文中对编程的贡献有如欧几里德对几何的贡献.1 他向我们展示了,在只给定几个简单的操作符和一个表示函数的记号的基础上, 如何构造出一个完整的编程语言. 麦卡锡称这种语言为Lisp, 意为List Processing, 因为他的主要思想之一是用一种简单的数据结构表(list)来代表代码和数据.
感谢保罗格雷厄姆,他用浅显易懂的语言将Lisp的根源和实质展现在我们面前,令我们能够幸运地零距离体验Lisp的这种“超凡的美”
如果你理解了约翰麦卡锡的eval, 那你就不仅仅是理解了程序语言历史中的一个阶段. 这些思想至今仍是Lisp的语义核心. 所以从某种意义上, 学习约翰麦卡锡的原著向我们展示了Lisp究竟是什么. 与其说Lisp是麦卡锡的设计,不如说是他的发现. 它不是生来就是一门用于人工智能, 快速原型开发或同等层次任务的语言. 它是你试图公理化计算的结果(之一).
随着时间的推移, 中级语言, 即被中间层程序员使用的语言, 正一致地向Lisp靠近. 因此通过理解eval你正在明白将来的主流计算模式会是什么样.
References
The Roots of Lisp Paul Graham. Draft, January 18, 2002.
LISt Primer Colin Allen & Maneesh Dhagat.Tue Feb 6, 2001.(http://mypage.iu.edu/~colallen/lp/lp.html)


猜你喜欢
- 将数据存储在不同的数据结构中时,搜索是非常基本的必需条件。最简单的方法是遍历数据结构中的每个元素,并将其与您正在搜索的值进行匹配。这就是所谓
- numpy库概述numpy库处理的最基础数据类型是由同种元素构成的多维数组,简称为“数组”数组的特点:数组中所有元素的类型必须相同数组中元素
- 例如有这么一个查询语句:select * from server where ip in (....)同时一个存放ip 的列表 :['
- 查看两个数据库的同名表的字段名差异问题描述开发过程中有多个测试环境,测试环境 A 加了字段,测试环境 B 忘了加,字段名对不上,同一项目就报
- 前言在Django使用Celery异步发送邮件的过程中,遇到Celery日志提示任务已接收,但实际上任务并没有执行,解决后特此记录。使用版本
- 项目:基于Pymysql的专家随机抽取系统引入库函数:>>> import treelib>>> fro
- 运用Jmeter正则提取器,可以从请求的响应结果中取到需要的内容,从而实现关联。关联是请求与请求之间存在数据依赖关系,需要从上一个请求获取下
- 可扩展标记语言 (XML) 是用于描述数据集内容以及应如何将数据输出到设备上或如何在 Web 页上显示数据的语言。标记语言的创建来源于出版商
- 以前学习ASP.NET MVC时,学习与应用,操作过数据显示,添加,编辑,更新和删除等功能。很多方法是相通的,看自己是怎样来进行方便,快捷,
- SQL Server数据库用视图来处理复杂的数据查询关系是本文我们主要要介绍的内容,该内容是这样想到的:在辅助教务系统那块的时候,我做的一个
- 问题背景我创建了一个函数,里面包含了一个获取当前执行文件路径的代码current_path = os.path.dirname(os.pat
- 要说2017年什么技术最火爆,无疑是google领衔的深度学习开源框架Tensorflow。本文简述一下深度学习的入门例子MNIST。深度学
- 核心代码:#!/usr/bin/python#-*- coding:gbk -*-#设置源文件输出格式import sysimport ge
- 在对浏览器兼容性要求越来越高的时候,大家是否正在寻找一个完整的解决方案呢?继《[原]最新CSS兼容方案》之后,更新的CSS hack出炉啦,
- 目录1. 简介2. 示例代码13. 示例代码24. 启动异常1. 简介Gunicorn(Green Unicorn)是给Unix用的WSGI
- 在我们关于SQL服务器安全系列的这文章里,我们的目标是向你提供安全安装SQL服务器所需要的工具和信心,这样的话,你有价值的数据就会受到保护,
- JavaScript lastIndexOf 方法lastIndexOf 方法用于计算指定的字符串在整个字符串中最后一次出现的位置,并返回该
- $str = '中华人民共和国123456789abcdefg'; echo preg_match("/^[u4e
- python函数的闭包问题(内嵌函数)>>> def func1():... print ('fun
- 目录1.获取所有顶层窗口2.手动选择需要设置老板键的程序3.隐藏或显示选中程序4.设置显示隐藏快捷键5.最终效果主要实现目标:为多个指定的程