- 論壇徽章:
- 5
|
回復(fù) 40# lcqtdwj
lisp復(fù)雜程度一點(diǎn)都不高。我一句話就能解釋明白,所謂“l(fā)isp復(fù)雜程度高”是因?yàn)閘isp太靈活,你想做啥就做啥,而對(duì)于你想做的,有各種各樣已經(jīng)規(guī)定好的實(shí)現(xiàn)(包括if和lambda),而這些東西太多了,你才會(huì)覺(jué)得復(fù)雜。
lisp的本質(zhì),一句話就能說(shuō)明白:程序是以S-exp表示的廣義表,對(duì)程序的求值(運(yùn)算、執(zhí)行),本質(zhì)上是對(duì)廣義表的求值,這是一個(gè)遞歸過(guò)程:對(duì)廣義表的第一個(gè)元素求值,并決定如何對(duì)其他元素進(jìn)行求值。完了。
比如(display (if (< a 1) 'a 'b)),先求值(display ...),首先根據(jù)描述對(duì)display求值:他是個(gè)函數(shù),那么函數(shù)的求值方式是對(duì)其所有后繼子項(xiàng)求值,那么開始對(duì)(if ...)求值,if是個(gè)special-form,他的求值方式是對(duì)第二項(xiàng)進(jìn)行求值,如果是真就對(duì)第三項(xiàng)進(jìn)行求值,否則就對(duì)第四項(xiàng)進(jìn)行求值………………
這個(gè)過(guò)程說(shuō)起來(lái)復(fù)雜,實(shí)際上就是一個(gè)多叉樹的遍歷而已,任何語(yǔ)言都可以很簡(jiǎn)單地做到(所以說(shuō)ruby能簡(jiǎn)單實(shí)現(xiàn)scheme真不是什么很自豪的事情),只是lisp特別靈活,它通過(guò)第一個(gè)元素對(duì)這個(gè)遍歷過(guò)程進(jìn)行了控制。你可以認(rèn)為lisp特別適合于dfs搜索功能,當(dāng)然這就是“l(fā)isp適合人工智能”這種論斷的原因。
那lisp的問(wèn)題在哪兒呢?在于效率。如上所說(shuō),要根據(jù)定義去執(zhí)行l(wèi)isp程序出乎人意料的簡(jiǎn)單,問(wèn)題是性能就不好說(shuō)了。ruby本來(lái)就慢,用這種方式求值lisp沒(méi)什么問(wèn)題,但是如果你是正兒八經(jīng)去考慮高效地執(zhí)行l(wèi)isp程序,你不得不考慮很多問(wèn)題:lisp到字節(jié)碼甚至機(jī)器碼的翻譯(為了jit或者效率)、cons的高效存儲(chǔ)、輕量級(jí)編譯器的實(shí)現(xiàn)、垃圾回收的效率等等等等,這才是lisp的難點(diǎn)所在,為了克服這些難點(diǎn),實(shí)現(xiàn)要么減少了lisp的靈活性(不允許修改+-*/神碼的),要么體積會(huì)很大(以同時(shí)支持靈活性和效率),這才是lisp不容易實(shí)用的原因。
但是你必須承認(rèn),真正做到了這點(diǎn)的lisp效率是ruby的300多倍(參看programming language benchmark game),而做不到這點(diǎn)的lisp(如用ruby實(shí)現(xiàn)的lisp)本質(zhì)上就是個(gè)toy而已。
最后說(shuō)說(shuō)ruby吧。這是我第一門腳本語(yǔ)言。最開始對(duì)它是很有好感的,但是因?yàn)榱私獾剿莗erl的后繼,我就開始學(xué)習(xí)perl,感覺(jué)perl太難學(xué)就轉(zhuǎn)了python,后來(lái)我常用perl(工作中)和python(私下里),就對(duì)ruby生疏了。作為一門perl的后繼語(yǔ)言,ruby無(wú)疑是目標(biāo)明確的——它拉低了編程的門檻(至于這個(gè)目標(biāo)是不是有益去問(wèn)OwnWaterloo吧),然而ruby自身也有很多問(wèn)題,第一個(gè)就是翻譯的問(wèn)題了,第二個(gè)就是效率問(wèn)題。ruby的效率低一方面用的是yacc而不是自行實(shí)現(xiàn)的翻譯器,另一方面它的執(zhí)行方式和樸素的lisp非常像——它也是執(zhí)行語(yǔ)法樹的!而且是以一種寫死的遍歷方式進(jìn)行執(zhí)行,這種方式我看是揚(yáng)短避長(zhǎng)了。它沒(méi)得到lisp的靈活性,反而損失了性能,這是得不償失的。
由此可以看出ruby對(duì)真正元編程的支持了,目前是很弱的,然而應(yīng)該有足夠的潛力達(dá)到很好的支持水平。而這本書里面提到的“元編程”,我覺(jué)得實(shí)在是不能被稱為元編程——這種元編程不是通過(guò)生成代碼來(lái)實(shí)現(xiàn)的,對(duì)效率沒(méi)有任何額外的好處,只是“運(yùn)行時(shí)獲取程序所有信息”而已,最多算是“元執(zhí)行”或者“元計(jì)算”。所謂元編程,即“生成程序的程序”,最初是為了可維護(hù)性(如檢查)和效率(如直接生成復(fù)雜代碼的執(zhí)行結(jié)果),而這些在單趟的ruby模型下是做不到的,除非你用ruby去生成ruby代碼:用ruby寫DSL來(lái)描述需求、DSL產(chǎn)生數(shù)據(jù)結(jié)構(gòu)、數(shù)據(jù)結(jié)構(gòu)再產(chǎn)生ruby代碼,再執(zhí)行產(chǎn)生的ruby代碼。如果是這樣那還有點(diǎn)看頭,不過(guò)ruby做到這個(gè)也就平淡無(wú)奇了,看看lua的一個(gè)綁定庫(kù)的DSL吧:
- require 'lbind'.export(_ENV)
- require 'lbind.types'.export(_ENV)
- module 'gd' {
- export = true,
- include "gd.h";
- subfiles {
- --"gdImage.bind.lua";
- };
- object "gdImage" {
- method "new" :cname "gdImageCreate"
- (int "sx", int "sy") :rets(selfType:ptr());
- method "newTrueColor" :cname "gdImageCreateTrueColor"
- (int "sx", int "sy") :rets(selfType:ptr());
- method "delete" () :alias "close" :cname "gdImageDestroy";
- method "color_allocate" :cname "gdImageColorAllocate"
- (int "r", int "g", int "b");
- method "line" :cname "gdImageLine"
- (int "x1", int "y1", int "x2", int "y2", int "color");
- include "errno.h";
- include "string.h";
- method "toPNG" (char:const():ptr "name") :body [[
- FILE *pngout = fopen(name, "wb");
- if (pngout == NULL) {
- lua_pushnil(L);
- lua_pushstring(L, strerror(errno));
- return 2;
- }
- gdImagePng(self, pngout);
- fclose(pngout);
- lua_pushboolean(L, 1);
- return 1;
- ]];
- };
- };
復(fù)制代碼 ruby能產(chǎn)生這么緊湊自然的DSL么? |
|