欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時間: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);
};

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

> [isNull,[_,a]]
[]
> [isNull. [_,[]]]
t
函數(shù):[and,x,y]返回t如果它的兩個自變量都是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]取兩個表并返回它們的連結(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òu)成的表,雙元素表是相應(yīng)位置的x,y的元素對.
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中第一個符合如下條件的表的第二個元素:它的第一個元素是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)在的問題是我們必須要定義一個引用的反函數(shù)f,令[f,[_,e]] = e
而顯然地ret正是這樣一個函數(shù)
[map,x,y]期望x是原子,y是一個表,如果[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中的每個元素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á)式等等.也許算是一個優(yōu)美的表示法, 那下一步呢? 現(xiàn)在驚喜來了. 我們可以寫一個函數(shù)作為我們語言的解釋器:此函數(shù)取任意Lisp表達(dá)式作自變量并返回它的值. 如下所示:
LispScript.Run(
 [defun,'_eval',['e','a'],
  [ret,[maplist,[_,'e'],'a']]
 ]
);

_eval.的簡潔程度或許超出了我們原先的預(yù)想,于是這樣我們獲得了LispScrip實(shí)現(xiàn)的一個完整的自身的解析器!
讓我們回過頭考慮一下這意味著什么. 我們在這兒得到了一個非常優(yōu)美的計(jì)算模型. 僅用quote,atom,eq,car,cdr,cons,和cond, 我們定義了函數(shù)_eval.,它事實(shí)上實(shí)現(xiàn)了我們的語言,用它可以定義和(或)動態(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如果它的自變量有一個為t,否則返回[]
LispScript.Run(
 [defun,'or',['x','y'],
  [not,[and,[not,'x'],[not,'y']]]]
);

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

相關(guān)文章

  • JS如何輸出26個英文字符

    JS如何輸出26個英文字符

    這篇文章主要介紹了JS如何輸出26個英文字符問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 小程序?qū)崿F(xiàn)搜索框

    小程序?qū)崿F(xiàn)搜索框

    搜索框無論是在電商網(wǎng)站還是小程序中都很常見,這篇文章主要就為大家詳細(xì)介紹了小程序如何實(shí)現(xiàn)搜索框,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Javascript閉包演示代碼小結(jié)

    Javascript閉包演示代碼小結(jié)

    有個網(wǎng)友問了個問題,如下的html,為什么點(diǎn)擊所有的段落p輸出都是5,而不是alert出對應(yīng)的0,1,2,3,4。
    2011-03-03
  • 判定對象是否為window的js代碼

    判定對象是否為window的js代碼

    這是一個非常有趣的題目。我們先從Object.prototype.toString入手,看能否解決它。
    2010-02-02
  • JS設(shè)計(jì)模式之?dāng)?shù)據(jù)訪問對象模式的實(shí)例講解

    JS設(shè)計(jì)模式之?dāng)?shù)據(jù)訪問對象模式的實(shí)例講解

    下面小編就為大家?guī)硪黄狫S設(shè)計(jì)模式之?dāng)?shù)據(jù)訪問對象模式的實(shí)例講解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 瀏覽器復(fù)制插件zeroclipboard使用指南

    瀏覽器復(fù)制插件zeroclipboard使用指南

    ZeroClipboard 是國外大神開發(fā)的一個用于剪貼板復(fù)制的 JS 插件,它是基于 Flash 來實(shí)現(xiàn)跨瀏覽器的復(fù)制功能的。當(dāng)我們使用 ZeroClipboard 的時候,它會悄悄隱藏一個小小的 Flash 影片(swf),不會對我們的用戶界面造成影響。我們只需要借助它實(shí)現(xiàn)復(fù)制功能就行了。
    2016-03-03
  • Javascript 實(shí)現(xiàn)微信分享(QQ、朋友圈、分享給朋友)

    Javascript 實(shí)現(xiàn)微信分享(QQ、朋友圈、分享給朋友)

    這篇文章主要介紹了Javascript 實(shí)現(xiàn)微信分享(QQ、朋友圈、分享給朋友)的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • JavaScript實(shí)現(xiàn)左右滾動電影畫布

    JavaScript實(shí)現(xiàn)左右滾動電影畫布

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)左右滾動電影畫布,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • 使用透明效果來自定義文件上傳按鈕控件樣式

    使用透明效果來自定義文件上傳按鈕控件樣式

    處于安全上的考慮,input[type="file"] 的文件選擇按鈕樣式并不能隨意修改(不過可以修改input 的透明度),可能會跟設(shè)計(jì)師的設(shè)計(jì)格格不入,這時可以使用透明效果來自定義上傳按鈕
    2012-12-12
  • JavaScript判斷瀏覽器類型的方法

    JavaScript判斷瀏覽器類型的方法

    這篇文章主要介紹了JavaScript判斷瀏覽器類型的方法,可實(shí)現(xiàn)針對IE、火狐、谷歌等瀏覽器的判斷,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-02-02

最新評論