Lisp 能被用來幹什麼?
我曾經跟趙余說過,《歌德爾,埃舍爾,巴赫,集異璧之大成》和《計算機程序的構造與解釋》同看,就像同時吃花生米和豆腐乾一樣相得益彰。實際上這其中每一本都讓我高潮連連。我一直找不到更合適的比喻,直到看到《華爾街之狼》里 Leonardo怎樣貫通了性與毒品。
用一個小例子來一窺堂奧。這個小例子叫WU謎題,它出現在《GEB》的第一章。這個謎題是「你能產生WU么?」一開始的時候,我們有一個符號串WI,有下面幾個規則:1,如果一個歸你所有的符號串結尾是I,則可以在後面加上一個U。
2,如果有Wx,那麼Wxx也歸你所有。e.g. WUI=&>WUIUI3,如果符號串中有III,那麼可以用U代替III。4,如果符號串中有UU,那麼可以去掉它。規則就是這些,現在可以試試找出WU了,能夠找出來的第一個人請把應用規則的序列方式告訴我,我請他吃飯並分享這其中的況味。這是一個簡單的形式系統,在這個形式系統中,WI被稱為」公理「,由它產生出的符號串被稱作」定理「。四條規則被稱作」推理規則「。由」公理「出發依次利用」推理規則「得到某」定理「的過程被稱為"推導」。"推導「這一概念是向」證明「概念看齊的,但比後者要樸素一點。這種定義明晰的重複性工作最適合用電腦來做。我的默認語言是scheme。判斷一個語言好壞有很多標準,我傾向於選擇其中最直觀的一個,那就是在描述眾多具有普遍意義的問題時,代碼總長度最短的是最好的。關於這個直覺我在之前的一篇討論什麼是更好的語言(不只是程序語言)時闡述過。——talk is cheap, show me the code——定義「公理」(define init (list (list m i)))
定義「推理規則」(define (operator lis) (define (rule_1 x) (define (end lis) (if (null? (cdr lis)) (car lis) (end (cdr lis)))) (if (eq? (end x) i) (append x (list u)))) (define (rule_2 x) (append x (cdr x))) (define (rule_3 x)(cond ((&> (length x) 3)
(cond ((and (eq? (cadr x) i) (eq? (caddr x) i) (eq? (cadddr x) i)) (append (list m u) (cddddr x))) (else ()))) (else ()))) (define (rule_4 x) (cond ((or (null? x) (null? (cdr x))) x) ((and (eq? (car x) u) (eq? (cadr x) u)) (rule_4 (cddr x))) (else (cons (car x) (rule_4 (cdr x)))))) (define (erase seq) (filter (lambda(x) (not (null? x))) seq))(erase (list (rule_1 lis) (rule_2 lis) (rule_3 lis) (rule_4 lis)))
)定義「記憶」(define dictionary init)(define (in? value lis)
(or (equal? value (car lis)) (and (not (null? (cdr lis))) (in? value (cdr lis)))))定義「推導」(define (expand seqs) (define (erase_repeat lis) (cond ((null? lis) ())(else (cons (car lis) (filter (lambda(x) (not (equal? x (car lis)))) (erase_repeat (cdr lis)))))))
(define (pre-expand lis) (if (null? lis) () (append (operator (car lis)) (pre-expand (cdr lis))))) (define result (filter (lambda(x) (not (in? x dictionary))) (erase_repeat (pre-expand seqs)))) (begin (set! dictionary (append dictionary result)) result))檢驗目標」定理「是否能夠被」推導「出來
(define object (list m u))(define (f a) (if (in? object a) yeah (f (expand a))))(f init)——talk is not cheap,it turns into code——
在接受了「公理」和「推理規則」之後,我們可以選擇盲目地試一試,在不知不覺中理解這套規則,也可以用scheme來翻譯這套規則。兩種方式都很必要。在進行前者時會產生一種微妙的心理活動,即跳出這個形式系統,看看我們到底在做什麼,系統中暗含了哪些抽象的現象,比如,只有三個字母,每個字元串開頭都是M,等等,這種現象在GEB中被稱作metathinking。第二種思考方式,相應地,就是thinking within the system, 在scheme優良的抽象風格下,系統顯示出了其內部的結構。接下來重點闡述後者。我們首先定義了「公理」,並將「公理」作為唯一一條語句寫入了一個「知識庫」,然後嘗試將四條「推理規則」應用於「公理」,合理的應用結果作為」一級定理「,一方面被寫入「知識庫」,另一方面作為"二級定理"的母定理,即繼續進行」推理「的材料使用,直到某一級定理包含了目標定理,整個推理過程結束。挺笨的。如果一個人掉入了所謂的」思維定勢「,他就變得像這段程序一樣笨了。我們來看一下結果:1 ]=&> (expand init);Value 12: ((m i u) (m i i))
1 ]=&> dictionary
;Value 13: ((m i) (m i u) (m i i))
1 ]=&> (expand (expand (expand init)))
;Value 14: ((m i u u u) (m i u u i u u) (m i u u i u) (m i u i u i u i u) (m i u u i) (m i u i i u i) (m i u i i i) (m i i i i i i i i) (m u i))
1 ]=&> dictionary
;Value 15: ((m i) (m i u) (m i i) (m i u u) (m i u i u) (m i u i) (m i i i i) (m i u u u) (m i u u i u u) (m i u u i u) (m i u i u i u i u) (m i u u i) (m i u i i u i) (m i u i i i) (m i i i i i i i i) (m u i))
1 ]=&> (f init)
;Aborting!: out of memory
;GC #97: took: 0.80 (35%) CPU time, 0.80 (36%) real time; free: 2752857;GC #98: took: 0.70 (88%) CPU time, 0.70 (99%) real time; free: 2752937多麼遺憾呢。StackOverFlow。其實這不難理解。如果那麼容易就能推導出來,我怎麼會許下請你吃飯的諾言呢。
在字元串複雜到一定程度之後,每一條「推理規則」都是合理的,因為每一條「推理規則」合理應用於某一字元串都只產生一條「定理」(這裡沒有考慮延遲應用),即」n級定理"的數目是「(n-1)級定理」數目的4的(n-1)次方倍。"0級定理「,即「公理」,有1個,則n級定理有4^n個。如果不過濾重複定理的話,在經過n次「推導」後「知識庫」里的「定理」數目大概是1/3(4^(n+1)-1)個。Bomb!」推導「需要metathinking。我們在摸索的時候,系統的模式會悄無聲息地浮現在腦海中。你不僅可以看出這個模式,而且通過檢查那些規則,還可以理解這個模式。這展示了人與機器的區別。這個區別在於:機器有可能在做某件事情時不去觀察,而人不可能不去觀察。能夠跳出正在進行的工作並且看一下已經做了些什麼,這是智能固有的特點。我已經不知道自己抄了多少GEB中的句子了,如果可以,我想把它全文打下來,用scheme去解釋裡面的每一個小故事。如果你期待Lisp有什麼「神奇」之處,可以做別的語言做不到的事情,你可能會失望的
- Lisp沒有任何神奇之處,它的核心就是一個以s-expression格式為輸入的eval而已。Nothing more, nothing less
- Lisp的macro功能更加不是什麼「神奇」的東西。任何解釋性語言的eval都接受動態數據,構造過程用戶可以自由發揮;用戶如果不喜歡語言內置的構造方式,自己可以寫一個,只要eval認就行。甚至C、C++、Java、C#這些編譯型的語言,只要能驅動編譯器,用戶一樣可以自己寫一個「macro」出來(或者叫做generate code on-the-fly)
- Lisp由於缺乏用來區分語義的語法變化,導致最後的代碼雖然可以很「緊湊」(緊湊也不代表演算法複雜度更優),但是可讀性和提示性不夠高。《Coders at Work》裡面的使用Lisp的先驅也說了因為這個原因後來不寫Lisp了
學之生,用之死。
強行用lisp來拉高函數的計算速度。曾經寫過一些基礎的解釋器,對common lisp里大部分內置函數都可以應用,代碼行數僅八十行。用lisp寫一些自動機,隨機生成器其實比其他語言還要簡單。
我用它來寫app吧。lisp app項目地址:evilbinary/scheme-lib
我正在學習 autocad LISP 算是 LISP的一個分支把 .用來解決我在工程製圖上的問題。
1. Racket, SBCL, Clozure, Emacs Lisp ,Slime, and Clojure等等 ,實現了哪些就可以做哪些2. 就算用的是其他的語言也可以對比學習metaprogramming, closure, clos ,clim等等優秀的思想和實現
作為一門普遍意義上的general purpose編程語言,Lisp可以做其它語言也能做的事情,只是有的可能有優勢,有的可能不如其它語言。
ACL2是一個用CommonLisp實現的用於做證明的工具,在它的官網上面說到,AMD用ACL2來驗證Athon處理器的浮點數計算的正確性。學lisp是學習其中的思想,用這個語言作為其他語言的起點。在lisp中有太多強大的變成思想需要自己慢慢探索的,這是其他語言沒它強大的地方
或許可以用它做個MUD.
lisp不能幹什麼?
只有想不到的,沒有做不到的Allegro Common Lisp Success StoriesFranz Inc: Allegro Common Lisp and Common Lisp Products
AutoCAD的二次開發使用Visual Lisp。
推薦閱讀:
※先學lisp好還是先學haskell好?
※對 Lisp 新手來說,學習哪種方言、使用哪些參考書和開發軟體更適合?
※SICP換零錢迭代方法實現,是如何寫的?
※根據遞推關係,如何編程計算這個數列的前10項?
※入門 Lisp 有哪些在線資料?
TAG:Lisp |