最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

極致之美——百行代碼實(shí)現(xiàn)全新智能語言第2/6頁(yè)

 更新時(shí)間:2007年03月14日 00:00:00   作者:  

我們可以這樣表示此函數(shù) 
[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);
};

我們簡(jiǎn)記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]]]]]]
偶然地我們?cè)谶@兒看到如何寫cond表達(dá)式的缺省子句. 第一個(gè)元素是't的子句總是會(huì)成功的. 于是 
[cond,[x,y],[[_,true],z]]
等同于我們?cè)谀承┱Z言中寫的 
if x then y else z 
對(duì)于函數(shù)調(diào)用,具有如下結(jié)構(gòu):[FunName,[_,args]]
其中FunName是函數(shù)名稱,[_,args]是指定參數(shù)引用列表args
注意[FunName,args]也是合法的,但是和[FunName,[_,args]]有所區(qū)別,對(duì)于前者,指令在被調(diào)用之前先計(jì)算args的值,把計(jì)算出的值作為參數(shù)列表代入函數(shù)計(jì)算(期望args計(jì)算結(jié)果為L(zhǎng)ist),而后者的args參數(shù)列表在函數(shù)指令調(diào)用時(shí)才被計(jì)算
到這里為止我們很高興地看到LispScript已經(jīng)可以不依賴于javascript來擴(kuò)展了
現(xiàn)在我們可以直接用LispScript定義一些新函數(shù)了:
函數(shù):[isNull,x]測(cè)試它的自變量是否是空表.
LispScript.Run(
 [defun,'isNull',['x'],
  [eq,'x',[_,NIL]]]
);

> [isNull,[_,a]]
[]
> [isNull. [_,[]]]
t
函數(shù):[and,x,y]返回t如果它的兩個(gè)自變量都是t, 否則返回[].
LispScript.Run(
 [defun,'and',['x','y'],
  [cond,['x',[cond,['y',true],[true,NIL]],
   [true,NIL]]]]
);

> [and,[atom,[_,a]],[eq,[_,a],[_,a]]]
t
> [and,[atom,[_,a]],[eq,[_,a],[_,b]]]
[]
函數(shù):[not,x]返回t如果它的自變量返回[],返回[]如果它的自變量返回t.
LispScript.Run(
 [defun,'not',['x'],
  [cond,['x',NIL],
        [true,true]]]
);

> [not,[eq,[_,a],[_,a]]]
[]
> [not,[eq,[_,a],[_,b]]]
t
函數(shù):[append,x,y]取兩個(gè)表并返回它們的連結(jié).
LispScript.Run(
 [defun,'append',['x','y'],
  [cond,[[isNull,'x'],'y'],
    [true,[cons,[car,'x'],['append',[cdr,'x'],'y']]]]]
);

> [append,[_,[a,b]],[_,[c,d]]]
[a,b,c,d]
> [append,[], [_,[c,d]]]
[c,d]
函數(shù):[pair,x,y]取兩個(gè)相同長(zhǎng)度的表,返回一個(gè)由雙元素表構(gòu)成的表,雙元素表是相應(yīng)位置的x,y的元素對(duì).
LispScript.Run(
 [defun,'pair',['x','y'],
  [cond,
   [[and,[isNull,'x'],[isNull,'y']],NIL], 
   [[and,[not,[atom,'x']],[not,[atom,'y']]],
    [append,[[[car,'x'],[car,'y']]],['pair',[cdr,'x'],[cdr,'y']]]
   ]]]
);

> [pair,[_,[x,y,z]],[_,[a,b,c]]]
[[x,a],[y,b],[z,c]]
[assoc,x,y]取原子x和形如pair函數(shù)所返回的表y,返回y中第一個(gè)符合如下條件的表的第二個(gè)元素:它的第一個(gè)元素是x.
LispScript.Run(
 [defun,'assoc',['x','y'],
  [cond,[[eq,[car,[car,'y']],'x'],[car,[cdr,[car,'y']]]],
   [[isNull,'y'],NIL],[true,['assoc','x',[cdr,'y']]]]]
);

> [assoc,[_,x],[_,[[x,a],[y,b]]]]
a
> [assoc,[_,x],[_,[[x,new],[x,a],[y,b]]]]
new
[ret,e]返回表達(dá)式計(jì)算結(jié)果
LispScript.Run(
 [defun,'ret',['e'],[car,['e']]]
);

[str,e]返回表達(dá)式計(jì)算結(jié)果的引用
LispScript.Run(
 [defun,'str',['e'],[_,[_,'e']]]
);

我們來看一下為什么要定義ret函數(shù):
我想通過前面的解釋和實(shí)際應(yīng)用大家已經(jīng)理解了引用(quote)的重要性,并且很容易證明:[[_,e]] = [e]
現(xiàn)在的問題是我們必須要定義一個(gè)引用的反函數(shù)f,令[f,[_,e]] = e
而顯然地ret正是這樣一個(gè)函數(shù)
[map,x,y]期望x是原子,y是一個(gè)表,如果[assoc,x,y]非空返回[assoc,x,y]的值否則返回x
LispScript.Run(
 [defun,'map',['x','y'],
  [cond,[[isNull,[assoc,'x','y']],'x'],[true,[assoc,'x','y']]]]
);

[maplist,x,y]期望x和y都是表,返回由x中的每個(gè)元素t求[map,t,y]的結(jié)果構(gòu)成的表
LispScript.Run(
 [defun,'maplist',['x','y'],
  [cond,
   [[atom,[_,'x']],[map,'x','y']],
   [true,[cons,['maplist',[car,[_,'x']],'y'],['maplist',[cdr,[_,'x']],'y']]]
  ]
 ]
);

因此我們能夠定義函數(shù)來連接表,替換表達(dá)式等等.也許算是一個(gè)優(yōu)美的表示法, 那下一步呢? 現(xiàn)在驚喜來了. 我們可以寫一個(gè)函數(shù)作為我們語言的解釋器:此函數(shù)取任意Lisp表達(dá)式作自變量并返回它的值. 如下所示:
LispScript.Run(
 [defun,'_eval',['e','a'],
  [ret,[maplist,[_,'e'],'a']]
 ]
);

_eval.的簡(jiǎn)潔程度或許超出了我們?cè)鹊念A(yù)想,于是這樣我們獲得了LispScrip實(shí)現(xiàn)的一個(gè)完整的自身的解析器!
讓我們回過頭考慮一下這意味著什么. 我們?cè)谶@兒得到了一個(gè)非常優(yōu)美的計(jì)算模型. 僅用quote,atom,eq,car,cdr,cons,和cond, 我們定義了函數(shù)_eval.,它事實(shí)上實(shí)現(xiàn)了我們的語言,用它可以定義和(或)動(dòng)態(tài)生成任何我們想要的額外的函數(shù)和各種文法(這一點(diǎn)比較重要) 
其他(略為復(fù)雜)的擴(kuò)展:
下面我們定義變量的賦值操作[setq,paraName,paraValue]
LispScript.Run(
 [defun,'setq',['para','val'],
  [ret,[defun,'para',[],[_eval,'val']]]]
);

增加邏輯操作符or,[or,x,y]返回t如果它的自變量有一個(gè)為t,否則返回[]
LispScript.Run(
 [defun,'or',['x','y'],
  [not,[and,[not,'x'],[not,'y']]]]
);

增加循環(huán)控制foreach,[foreach,v,[paralist],[expr]]
foreach期望list是一個(gè)表,依次取表中的每一個(gè)原子作為expr的參數(shù)進(jìn)行計(jì)算,返回計(jì)算結(jié)果的表
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'"]]]]]
  ]
);

總結(jié)
現(xiàn)在該回過頭來看看我們究竟做了什么,以及這么做有什么意義了。
首先我們用javascript實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的向下遞歸的詞法分析器,它能對(duì)嵌套數(shù)組的每個(gè)原子進(jìn)行簡(jiǎn)單處理,加上幾個(gè)輔助函數(shù)(toEvalString(),Assert(),Element()和一個(gè)存放函數(shù)名稱的堆棧...簡(jiǎn)單來說我們僅用了數(shù)十行代碼實(shí)現(xiàn)了一種全新的“函數(shù)式”語言??LispScript的完整內(nèi)核。
接著我們定義了7種原始操作,它們分別是quote,atom,eq,car,cdr,cons和cond
然后(相對(duì)較復(fù)雜地),我們定義了三種用來描述和調(diào)用函數(shù)的標(biāo)記,它們分別是lambda, label以及defun,于是我們成功地用另外不到百行代碼實(shí)現(xiàn)了LispScript語言的核心環(huán)境。
接著(接下來的部分已經(jīng)可以完全獨(dú)立于javascript)我們用7種原始操作符和函數(shù)定義標(biāo)記defun定義出一些新的函數(shù),分別是:isNull,and,not,append,pair,assoc,ret和str
然后我們驚喜地發(fā)現(xiàn),可以僅用一行LispScript指令定義出自身的“解析器”??_eval函數(shù)
最后我們?cè)诖嘶A(chǔ)上定義出一些略為復(fù)雜的函數(shù),它們包括:or,setq,foreach和let,其中一些新函數(shù)帶給我們的新語言定義變量和處理循環(huán)的能力,加上前面實(shí)現(xiàn)的一些函數(shù),一個(gè)比較完善的基礎(chǔ)環(huán)境就搭建成了。
寫在最后:LispScript和Lisp
事實(shí)上我們依照[ref. Paul Graham.]的精彩描述用javascript實(shí)現(xiàn)了LispScript,毫無疑問,它是一種Lisp(或者Lisp風(fēng)格的函數(shù)式語言),盡管功能上還十分簡(jiǎn)陋,但它確實(shí)是符合Lisp的基本思想和擁有Lisp的基本特性。由于javascript數(shù)組文法的特點(diǎn),我用[]取代了[ref. Paul Graham]中的(),用逗號(hào)取代了空格作為分隔符。同[ref. Paul Graham]的文章以及目前一些標(biāo)準(zhǔn)(或者相對(duì)標(biāo)準(zhǔn))的Lisp不同的是,我根據(jù)javascript靈活的特點(diǎn)有意弱化了LispScript的語法結(jié)構(gòu),這樣使得LispScript更加靈活,也更加方便實(shí)現(xiàn),然而代價(jià)是一小部分的可維護(hù)性和安全性。
最后,LispScript還有許多需要完善的內(nèi)容,例如,最明顯地是它基本上還不具有基本的數(shù)值運(yùn)算能力(相對(duì)而言,符號(hào)操作能力已經(jīng)比較完善),另外對(duì)原子操作參數(shù)合法性的檢驗(yàn)、副作用, 連續(xù)執(zhí)行 (它得和副作用在一起才有用), 動(dòng)態(tài)可視域、復(fù)雜數(shù)據(jù)結(jié)構(gòu)支持以及注釋文法(這相當(dāng)重要!)也都是它所欠缺的,不過這些功能“都可以令人驚訝地用極少的額外代碼來補(bǔ)救”。
感謝約翰麥卡錫,這位天才早在數(shù)十年前就向我們展示了一種程序設(shè)計(jì)領(lǐng)域內(nèi)至今無人能超越的“極致的美”,他于1960年發(fā)表了一篇非凡的論文,他在這篇論文中對(duì)編程的貢獻(xiàn)有如歐幾里德對(duì)幾何的貢獻(xiàn).1 他向我們展示了,在只給定幾個(gè)簡(jiǎn)單的操作符和一個(gè)表示函數(shù)的記號(hào)的基礎(chǔ)上, 如何構(gòu)造出一個(gè)完整的編程語言. 麥卡錫稱這種語言為L(zhǎng)isp, 意為L(zhǎng)ist Processing, 因?yàn)樗闹饕枷胫皇怯靡环N簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)表(list)來代表代碼和數(shù)據(jù). 
感謝保羅格雷厄姆,他用淺顯易懂的語言將Lisp的根源和實(shí)質(zhì)展現(xiàn)在我們面前,令我們能夠幸運(yùn)地零距離體驗(yàn)Lisp的這種“超凡的美”
如果你理解了約翰麥卡錫的eval, 那你就不僅僅是理解了程序語言歷史中的一個(gè)階段. 這些思想至今仍是Lisp的語義核心. 所以從某種意義上, 學(xué)習(xí)約翰麥卡錫的原著向我們展示了Lisp究竟是什么. 與其說Lisp是麥卡錫的設(shè)計(jì),不如說是他的發(fā)現(xiàn). 它不是生來就是一門用于人工智能, 快速原型開發(fā)或同等層次任務(wù)的語言. 它是你試圖公理化計(jì)算的結(jié)果(之一). 
隨著時(shí)間的推移, 中級(jí)語言, 即被中間層程序員使用的語言, 正一致地向Lisp靠近. 因此通過理解eval你正在明白將來的主流計(jì)算模式會(huì)是什么樣.
References
The Roots of Lisp Paul Graham. Draft, January 18, 2002.
LISt Primer Colin Allen & Maneesh Dhagat.Tue Feb 6, 2001.(

相關(guān)文章

最新評(píng)論

城固县| 上杭县| 道真| 沂源县| 油尖旺区| 临武县| 晋江市| 伊金霍洛旗| 肃宁县| 若尔盖县| 尖扎县| 湖口县| 衡山县| 高雄县| 应城市| 星座| 开平市| 平陆县| 青田县| 黄冈市| 舞钢市| 自治县| 资源县| 阿拉尔市| 台前县| 广西| 鄂托克前旗| 台江县| 小金县| 饶平县| 龙口市| 报价| 旬邑县| 深水埗区| 准格尔旗| 来安县| 荣昌县| 浮山县| 祁阳县| 日土县| 临海市|