久久久精品一区ed2k-女人被男人叉到高潮的视频-中文字幕乱码一区久久麻豆樱花-俄罗斯熟妇真实视频

Lisp實(shí)例分析

今天小編給大家分享一下Lisp實(shí)例分析的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

創(chuàng)新互聯(lián)建站網(wǎng)站建設(shè)提供從項(xiàng)目策劃、軟件開發(fā),軟件安全維護(hù)、網(wǎng)站優(yōu)化(SEO)、網(wǎng)站分析、效果評(píng)估等整套的建站服務(wù),主營(yíng)業(yè)務(wù)為網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì),App定制開發(fā)以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。創(chuàng)新互聯(lián)建站深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

Lisp有豐富的內(nèi)置數(shù)據(jù)類型, 其中的整數(shù)和字符串和其他語(yǔ)言沒什么分別。像71或者”hello”這樣的值, 含義也和C++或者Java這樣的語(yǔ)言大體相同。真正有意思的三種類型是符號(hào)(symbol), 表和函數(shù)。這一章的剩余部分, 我都會(huì)用來介紹這幾種類型, 還要介紹Lisp環(huán)境是怎樣編譯和運(yùn)行源碼的。這個(gè)過程用Lisp的術(shù)語(yǔ)來說通常叫做求值。通讀這一節(jié)內(nèi)容, 對(duì)于透徹理解元編程的真正潛力, 以及代碼和數(shù)據(jù)的同一性, 和面向領(lǐng)域語(yǔ)言的觀念, 都極其重要。萬(wàn)勿等閑視之。我會(huì)盡量講得生動(dòng)有趣一些, 也希望你能獲得一些啟發(fā)。那好, 我們先講符號(hào)。

大體上, 符號(hào)相當(dāng)于C++或Java語(yǔ)言中的標(biāo)志符, 它的名字可以用來訪問變量值(例如currentTime, arrayCount, n, 等等), 差別在于, Lisp中的符號(hào)更加基本。在C++或Java里面, 變量名只能用字母和下劃線的組合, 而Lisp的符號(hào)則非常有包容性, 比如, 加號(hào)(+)就是一個(gè)合法的符號(hào), 其他的像-, =, hello-world, *等等都可以是符號(hào)名。符號(hào)名的命名規(guī)則可以在網(wǎng)上查到。你可以給這些符號(hào)任意賦值, 我們這里先用偽碼來說明這一點(diǎn)。假定函數(shù)set是給變量賦值(就像等號(hào)=在C++和Java里的作用), 下面是我們的例子:

set(test, 5)            // 符號(hào)test的值為5

set(=5)               // 符號(hào)=的值為5

set(test, "hello")      // 符號(hào)test的值為字符串"hello"

set(test, =)            // 此時(shí)符號(hào)=的值為5, 所以test的也為5

set(*"hello")         // 符號(hào)*的值為"hello"

好像有什么不對(duì)的地方? 假定我們對(duì)*賦給整數(shù)或者字符串值, 那做乘法時(shí)怎么辦? 不管怎么說, *總是乘法呀? 答案簡(jiǎn)單極了。Lisp中函數(shù)的角色十分特殊, 函數(shù)也是一種數(shù)據(jù)類型, 就像整數(shù)和字符串一樣, 因此可以把它賦值給符號(hào)。乘法函數(shù)Lisp的內(nèi)置函數(shù), 默認(rèn)賦給*, 你可以把其他函數(shù)賦值給*, 那樣*就不代表乘法了。你也可以把這函數(shù)的值存到另外的變量里。我們?cè)儆脗未a來說明一下:

3,4)          // 34, 結(jié)果是12

set(temp, *)    // *的值, 也就是乘法函數(shù), 賦值給temp

set(*3)       // 3賦予*

*(3,4)          // 錯(cuò)誤的表達(dá)式, *不再是乘法, 而是數(shù)值3

temp(3,4)       // temp是乘法函數(shù), 所以此表達(dá)式的值為34等于12

set(*, temp)    // 再次把乘法函數(shù)賦予*

*(3,4)          // 34等于12

再古怪一點(diǎn), 把減號(hào)的值賦給加號(hào):

set(+-)       // 減號(hào)(-)是內(nèi)置的減法函數(shù)

+(54)         // 加號(hào)(+)現(xiàn)在是代表減法函數(shù), 結(jié)果是54等于1

這只是舉例子, 我還沒有詳細(xì)講函數(shù)。Lisp中的函數(shù)是一種數(shù)據(jù)類型, 和整數(shù), 字符串,符號(hào)等等一樣。一個(gè)函數(shù)并不必然有一個(gè)名字, 這和C++或者Java語(yǔ)言的情形很不相同。在這里函數(shù)自己代表自己。事實(shí)上它是一個(gè)指向代碼塊的指針, 附帶有一些其他信息(例如一組參數(shù)變量)。只有在把函數(shù)賦予其他符號(hào)時(shí), 它才具有了名字, 就像把一個(gè)數(shù)值或字符串賦予變量一樣的道理。你可以用一個(gè)內(nèi)置的專門用于創(chuàng)建函數(shù)的函數(shù)來創(chuàng)建函數(shù),然后把它賦值給符號(hào)fn, 用偽碼來表示就是:

fn [a]

{

   return *(a, 2);

}

這段代碼返回一個(gè)具有一個(gè)參數(shù)的函數(shù), 函數(shù)的功能是計(jì)算參數(shù)乘2的結(jié)果。這個(gè)函數(shù)還沒有名字, 你可以把此函數(shù)賦值給別的符號(hào):

set(times-two, fn [a] {return *(a, 2)})

我們現(xiàn)在可以這樣調(diào)用這個(gè)函數(shù):

time-two(5)         // 返回10

我們先跳過符號(hào)和函數(shù), 講一講表。什么是表? 你也許已經(jīng)聽過好多相關(guān)的說法。表, 一言以蔽之, 就是把類似XML那樣的數(shù)據(jù)塊, 用s表達(dá)式來表示。表用一對(duì)括號(hào)括住, 表中元素以空格分隔, 表可以嵌套。例如(這回我們用真正的Lisp語(yǔ)法, 注意用分號(hào)表示注釋):

()                      ; 空表

(1)                     ; 含一個(gè)元素的表

(1 "test")              ; 兩元素表, 一個(gè)元素是整數(shù)1, 另一個(gè)是字符串

(test "hello")          ; 兩元素表, 一個(gè)元素是符號(hào), 另一個(gè)是字符串

(test (1 2"hello")    ; 三元素表, 一個(gè)符號(hào)test, 一個(gè)含有兩個(gè)元素12

; 表, 最后一個(gè)元素是字符串

當(dāng)Lisp系統(tǒng)遇到這樣的表時(shí), 它所做的, 和Ant處理XML數(shù)據(jù)所做的, 非常相似, 那就是試圖執(zhí)行它們。其實(shí), Lisp源碼就是特定的一種表, 好比Ant源碼是一種特定的XML一樣。Lisp執(zhí)行表的順序是這樣的, 表的第一個(gè)元素當(dāng)作函數(shù), 其他元素當(dāng)作函數(shù)的參數(shù)。如果其中某個(gè)參數(shù)也是表, 那就按照同樣的原則對(duì)這個(gè)表求值, 結(jié)果再傳遞給最初的函數(shù)作為參數(shù)。這就是基本原則。我們看一下真正的代碼:

(* 3 4)                 ; 相當(dāng)于前面列舉過的偽碼*(3,4), 即計(jì)算34

(times-two 5)           ; 返回10, times-two按照前面的定義是求參數(shù)的2

(3 4)                   ; 錯(cuò)誤, 3不是函數(shù)

(time-two)              ; 錯(cuò)誤, times-two要求一個(gè)參數(shù)

(times-two 3 4)         ; 錯(cuò)誤, times-two只要求一個(gè)參數(shù)

(set + -)               ; 把減法函數(shù)賦予符號(hào)+

(+ 5 4)                 ; 依據(jù)上一句的結(jié)果, 此時(shí)+表示減法, 所以返回1

(* 3 (+ 2 2))           ; 2+2的結(jié)果是4, 再乘3, 結(jié)果是12

上述的例子中, 所有的表都是當(dāng)作代碼來處理的。怎樣把表當(dāng)作數(shù)據(jù)來處理呢? 同樣的,設(shè)想一下, Ant是把XML數(shù)據(jù)當(dāng)作自己的參數(shù)。在Lisp中, 我們給表加一個(gè)前綴’來表示數(shù)據(jù)。

(set test '(1 2))       ; test的值為兩元素表

(set test (1 2))        ; 錯(cuò)誤, 1不是函數(shù)

(set test '(* 3 4))     ; test的值是三元素表, 三個(gè)元素分別是*34

我們可以用一個(gè)內(nèi)置的函數(shù)head來返回表的第一個(gè)元素, tail函數(shù)來返回剩余元素組成的表。

(head '(* 3 4))         ; 返回符號(hào)*

(tail '(* 3 4))         ; 返回表(3 4)

(head (tal '(* 3 4)))   ; 返回3

(head test)             ; 返回*

你可以把Lisp的內(nèi)置函數(shù)想像成Ant的任務(wù)。差別在于, 我們不用在另外的語(yǔ)言中擴(kuò)展Lisp(雖然完全可以做得到), 我們可以用Lisp自己來擴(kuò)展自己, 就像上面舉的times-two函數(shù)的例子。Lisp的內(nèi)置函數(shù)集十分精簡(jiǎn), 只包含了十分必要的部分。剩下的函數(shù)都是作為標(biāo)準(zhǔn)庫(kù)來實(shí)現(xiàn)的。

Lisp宏

我們已經(jīng)看到, 元編程在一個(gè)類似jsp的模板引擎方面的應(yīng)用。我們通過簡(jiǎn)單的字符串處理來生成代碼。但是我們可以做的更好。我們先提一個(gè)問題, 怎樣寫一個(gè)工具, 通過查找目錄結(jié)構(gòu)中的源文件來自動(dòng)生成Ant腳本。

用字符串處理的方式生成Ant腳本是一種簡(jiǎn)單的方式。當(dāng)然, 還有一種更加抽象, 表達(dá)能力更強(qiáng), 擴(kuò)展性更好的方式, 就是利用XML庫(kù)在內(nèi)存中直接生成XML節(jié)點(diǎn), 這樣的話內(nèi)存中的節(jié)點(diǎn)就可以自動(dòng)序列化成為字符串。不僅如此, 我們的工具還可以分析這些節(jié)點(diǎn), 對(duì)已有的XML文件做變換。通過直接處理XML節(jié)點(diǎn)。我們可以超越字符串處理, 使用更高層次的概念, 因此我們的工作就會(huì)做的更快更好。

我們當(dāng)然可以直接用Ant自身來處理XML變換和制作代碼生成工具?;蛘呶覀円部梢杂肔isp來做這項(xiàng)工作。正像我們以前所知的, 表是Lisp內(nèi)置的數(shù)據(jù)結(jié)構(gòu), Lisp含有大量的工具來快速有效的操作表(head和tail是最簡(jiǎn)單的兩個(gè))。而且, Lisp沒有語(yǔ)義約束, 你可以構(gòu)造任何數(shù)據(jù)結(jié)構(gòu), 只要你原意。

Lisp通過宏(macro)來做元編程。我們寫一組宏來把任務(wù)列表(to-do list)轉(zhuǎn)換為專用領(lǐng)域語(yǔ)言。

回想一下上面to-do list的例子, 其XML的數(shù)據(jù)格式是這樣的:

<todo name "housework">

<item priority "high">Clean the hose</item>

<item priority "medium">Wash the dishes</item>

<item priority "medium">Buy more soap</item>

</todo>

相應(yīng)的s表達(dá)式是這樣的:

(todo "housework"

(item (priority high) "Clean the house")

(item (priority medium) "Wash the dishes")

(item (priority medium) "Buy more soap"))

假設(shè)我們要寫一個(gè)任務(wù)表的管理程序, 把任務(wù)表數(shù)據(jù)存到一組文件里, 當(dāng)程序啟動(dòng)時(shí), 從文件讀取這些數(shù)據(jù)并顯示給用戶。在別的語(yǔ)言里(比如說Java), 這個(gè)任務(wù)該怎么做? 我們會(huì)解析XML文件, 從中得出任務(wù)表數(shù)據(jù), 然后寫代碼遍歷XML樹, 再轉(zhuǎn)換為Java的數(shù)據(jù)結(jié)構(gòu)(老實(shí)講, 在Java里解析XML真不是件輕松的事情), 最后再把數(shù)據(jù)展示給用戶。現(xiàn)在如果用Lisp, 該怎么做?

假定要用同樣思路的化, 我們大概會(huì)用Lisp庫(kù)來解析XML。XML對(duì)我們來說就是一個(gè)Lisp的表(s表達(dá)式), 我們可以遍歷這個(gè)表, 然后把相關(guān)數(shù)據(jù)提交給用戶??墒? 既然我們用Lisp, 就根本沒有必要再用XML格式保存數(shù)據(jù), 直接用s表達(dá)式就好了, 這樣就沒有必要做轉(zhuǎn)換了。我們也用不著專門的解析庫(kù), Lisp可以直接在內(nèi)存里處理s表達(dá)式。注意, Lisp編譯器和.net編譯器一樣, 對(duì)Lisp程序來說, 在運(yùn)行時(shí)總是隨時(shí)可用的。

但是還有更好的辦法。我們甚至不用寫表達(dá)式來存儲(chǔ)數(shù)據(jù), 我們可以寫宏, 把數(shù)據(jù)當(dāng)作代碼來處理。那該怎么做呢? 真的簡(jiǎn)單?;叵胍幌? Lisp的函數(shù)調(diào)用格式:

(function-name arg1 arg2 arg3)

其中每個(gè)參數(shù)都是s表達(dá)式, 求值以后, 傳遞給函數(shù)。如果我們用(+ 4 5)來代替arg1,那么, 程序會(huì)先求出結(jié)果, 就是9, 然后把9傳遞給函數(shù)。宏的工作方式和函數(shù)類似。主要的差別是, 宏的參數(shù)在代入時(shí)不求值。

(macro-name (+ 4 5))

這里, (+ 4 5)作為一個(gè)表傳遞給宏, 然后宏就可以任意處理這個(gè)表, 當(dāng)然也可以對(duì)它求值。宏的返回值是一個(gè)表, 然后有程序作為代碼來執(zhí)行。宏所占的位置, 就被替換為這個(gè)結(jié)果代碼。我們可以定義一個(gè)宏把數(shù)據(jù)替換為任意代碼, 比方說, 替換為顯示數(shù)據(jù)給用戶的代碼。

這和元編程, 以及我們要做的任務(wù)表程序有什么關(guān)系呢? 實(shí)際上, 編譯器會(huì)替我們工作,調(diào)用相應(yīng)的宏。我們所要做的, 僅僅是創(chuàng)建一個(gè)把數(shù)據(jù)轉(zhuǎn)換為適當(dāng)代碼的宏。

例如, 上面曾經(jīng)將過的C的求三次方的宏, 用Lisp來寫是這樣子:

(defmacro triple (x)

`(+ ~x ~x ~x))

(譯注: 在Common Lisp中, 此處的單引號(hào)應(yīng)當(dāng)是反單引號(hào), 意思是對(duì)表不求值, 但可以對(duì)表中某元素求值, 記號(hào)~表示對(duì)元素x求值, 這個(gè)求值記號(hào)在Common Lisp中應(yīng)當(dāng)是逗號(hào)。反單引號(hào)和單引號(hào)的區(qū)別是, 單引號(hào)標(biāo)識(shí)的表, 其中的元素都不求值。這里作者所用的記號(hào)是自己發(fā)明的一種Lisp方言Blaise, 和common lisp略有不同, 事實(shí)上, 發(fā)明方言是lisp高手獨(dú)有的樂趣, 很多狂熱分子都熱衷這樣做。比如Paul Graham就發(fā)明了ARC, 許多記號(hào)比傳統(tǒng)的Lisp簡(jiǎn)潔得多, 顯得比較現(xiàn)代)

單引號(hào)的用處是禁止對(duì)表求值。每次程序中出現(xiàn)triple的時(shí)候,

(triple 4)

都會(huì)被替換成:

(+ 4 4 4)

我們可以為任務(wù)表程序?qū)懸粋€(gè)宏, 把任務(wù)數(shù)據(jù)轉(zhuǎn)換為可執(zhí)行碼, 然后執(zhí)行。假定我們的輸出是在控制臺(tái):

(defmacro item (priority note)

`(block

(print stdout tab "Prority: " ~(head (tail priority)) endl)

(print stdout tab "Note: " ~note endl endl)))

我們創(chuàng)造了一個(gè)非常小的有限的語(yǔ)言來管理嵌在Lisp中的任務(wù)表。這個(gè)語(yǔ)言只用來解決特定領(lǐng)域的問題, 通常稱之為DSLs(特定領(lǐng)域語(yǔ)言, 或?qū)S妙I(lǐng)域語(yǔ)言)。

以上就是“Lisp實(shí)例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

網(wǎng)頁(yè)標(biāo)題:Lisp實(shí)例分析
文章鏈接:http://sd-ha.com/article24/gcjgje.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航微信公眾號(hào)、服務(wù)器托管軟件開發(fā)、網(wǎng)站設(shè)計(jì)、Google

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

小程序開發(fā)