zoukankan      html  css  js  c++  java
  • 解释器求值的那个夏天

    求值从何始?

    开始思考求值的实际意义是在自己要实现一个解释器的时候,那个时候很头疼,一直在思考求值的自然含义,怎样求值,求值会遇到的问题。甚至思考值本身的意义是什么?
    这可能是个很令人不屑一想的问题,试想在使用编程语言的时候,大多数时候是在思考算法,实现业务逻辑,架构设计,思考这个语言本身的问题,既不能加快开发,也不能明悟。

    我为什么思考?

    在我开始学习SICP的时候,我的小伙伴已经学到一半,并开始实现一个解释器,本来没打算写什么解释器,但是出于暑假无聊,我也"跟风"写了一个scheme解释器。
    我coding过半,完成了词法,语法解析部分之后,开始为这个空的global环境增加一些基本的过程,例如最基本的:

    +  -  *  /  lambda  define
    

    但是这时候我开始思考这些基本过程的意义是什么,scheme这门语言是允许overwrite一些方法的,比如用户可以:

    (define + -)
    

    这就意味着+的功能被修改成了原来-的功能,那么我开始反问: 既然这些方法可以被重写,那么我现在设置这些值是为了什么,反正这些规则是可以改变的,到底有什么意义?如果我这样做是错的,那么到否意味着我应该把握住自己的“权威”,禁止用户去修改这些我设定的初始值;如果是对的,那么如果用户胡乱重写这些方法,那么最后可能这门语言什么用都没了,再也找不到+的意义,也再也找不到-的意义,最后没有意义。
    这个问题我想了以后,发现是永远不可能有一个正确的答案,有的只是设计者的一些态度,世界本来就始于虚无,能够存在就是因爲创造,所以最后我将这些算数操作依然处理为用户可重写的,但是却保留了define,lambda这些关键字,纵然可以重新归于0,但不能缺乏创造。

    在哪求值?

    刚才我提到了global环境,环境便是值所在处,所谓猪肉长在猪身上,若要在环境中求值,必定先要在环境中注入值,譬如在global环境增加一个最常见的求阶乘的函数:

    (define factorial (lambda (n)
    	(if (= n 1)
    		1
    		(factorial (- n 1)))))
    

    在下次调用时只要身处这个global环境,就可以找到这个factorial函数:

    (factorial 3) => 6
    

    细心的朋友会问

    • n是怎么传到这个函数的计算里的?
    • 同时,还应该问=,-,甚至factorial是怎么被访问到的?

    计算需要求值环境,所以这一切的值的访问,需要环境,在计算时任何变量都会绑定到一个环境中,如果在环境中搜索到值,那么求值ok,否则undefined。(factorial 3)在计算的时候绑定了global环境。

    环境链

    环境如果是单一的,那么对于各个对象的私有状态是个巨大的挑战。试想coder1将name修改为'coder1',coder2将name修改为'coder2',当coder1读取name时,意外地发现竟然不是自己的名字。而为了实现两个coder各自的状态,就得在变量命名上要求不重复,更坏的情况是coder越来越多,这个问题越来越突出。
    利用私有环境可以维护各个对象的私有状态,coder1设置读取自己的name属性,就可以去这个环境中获得,而其它的变量依然可以去global中获取,所以环境链成了一个自然的解决方案,以下是(factorial 3)的计算环境:

    -GLOBAL
    ^       - => [procedure:minus]
    |       * => [procedure:multiple]
    |       factorial => [procedure:factorial]
    -ANONYMOUS COMPUTING ENVIRONMENT
    ^       n => 3
    |
    CURRENT
    

    (factorial 3)在求值函数体的时候,将当前的环境指向了这个为了当前计算而产生的匿名计算环境,里面有的就是通过参数传入的n,名字为n的变量便绑定到了这个值,而当求值失败后,解释器判断是否存在下一个环境,如果存在,那么求值将在环境链下个环境中求值,直到求值成功或环境链遍历结束,返回undefined。

    一个求值例子: javascript的this求值

    js的求值本质适合scheme一样的,不过是语法的略微不同,而js中的this的求值比较好玩,它是一个异数,它是和当前对象绑定的,解释器根据当前执行这个函数的对象来判断这个this的值,this是只读的。
    可以有几个有趣的例子来对this有个认识:

    1. global this

       var name = 'global';
       alert(this);       // [Object:Window]
       alert(this.name);  // 'gloabl'
      
    2. 新建对象里的this

       var name = 'global';
       var Coder = {
       	name : 'srggggg',
       	name2 : this.name,
       	name3 : name,
       	getName : function() {
       		return this.name;
       	},
       };
       alert(Coder.getName());  // 'srggggg'
       alert(Coder.name);  // 'srggggg'
       alert(Coder.name2);  // 'global'
       alert(Coder.name3());  // 'global'
      
    3. 嵌套的function的this

       var name = 'global';
       var Coder = {
       	name : 'srggggg',
       	getNameFunc : function() {
       		return function() {
       			return this.name;
       		};
       	}
       };
       alert(Coder.getNameFunc()());  // 'global'
      

    第一种情况是最直白的由于在global环境中求值,this就是global环境下的Window对象。
    第二种情况,this显式出现2次,隐式出现1次。

    • name2的定义中this是绑定到global中的Window对象,定义本身是一种求值过程,实际上是这次的define执行被绑定到了global环境,所以name2是'global'
    • name3的定义中没有this,但是由于name从global中被解析出来,所以可以看作this.name
    • getName函数定义中用到了this,这个this是真正绑定到Coder对象的,getName的函数体执行肯定是在Coder对象定义之后,因此this就不会在Coder定义过程中被绑定到global,而是绑定到最接近自己Coder对象。

    第三种情况,this对象绑定的是Window对象,说明了function本身不能作为this对象,Coder.getNameFunc返回的是一个function,Coder.getNameFunc()返回的是执行这个function返回的function,而如果function本身如何可以作为对象的话,那么根据第二个例子this绑定的是最近的object,那么this应该绑定的是getNameFunc这个"function object",可惜javascript并不把function真正作为一个可以充当this的对象,既然如此this就被绑定到了执行这个Coder.getNameFunc()的[Window Object]上了。

    // Another sample
    // Array Object
    var array = new Array();
    array.name = 'array';
    array[0] = function() { return this.name; };
    alert(array[0]()); // 'array'
    

    聊以此文,怀念我那纠结但是执着的暑假,在我的人生道路上留下一个印记

  • 相关阅读:
    IE6/IE7浏览器中"float: right"自动换行的解决方法
    IE6/IE7浏览器不支持display: inline-block;的解决方法
    如何解决两个li之间的缝隙
    input、button、a标签 等定义的按钮尺寸的兼容性问题
    在一个页面重复使用一个js函数的方法
    关于让input=text,checkbox居中的解决方法
    遮盖层实现(jQuery+css+html)
    button,input type=button按钮在IE和w3c,firefox浏览器区别
    前端-选项卡(菜单栏)
    形成人、机器、过程和数据的互联互通
  • 原文地址:https://www.cnblogs.com/pier2/p/eval.html
Copyright © 2011-2022 走看看