一直以來對Lisp語言懷有很崇敬的內心,《黑客與畫家》對Lisp更是推崇備至,雖然看了很多有關Lisp的介紹但都沒有機會去寫段程序試試,就像我對C++同樣,多少有點敬畏。這個週末花了很多時間來研究Lisp。
Lisp是古老的函數式語言,跟C,C++等命令式語言徹底不同的編程風格,但Lisp的方言不少,最後Lisp標準委員制定了Common Lisp,但內容很長,有1000多頁,所以功能比較強大;而Lisp的另一個主要分支就是Scheme,它的標準內容只有不到100頁,因此很是簡單,適合學術研究和大學計算機語言教學以及通常的工程應用。目前Lisp有在JVM上的實現,在.NET上的實現就是 IronScheme,因而我便開始選擇了IronScheme做爲Lisp研究的第一站。html
IronScheme在Codeplex上有開源項目, https://ironscheme.codeplex.com/ ,能夠下載它的源碼和編譯好的程序,在 https://ironscheme.codeplex.com/SourceControl/latest 能夠下載源碼,我下載時候的文件名是 ironscheme-103684,下載的源碼能夠用VS2008打開。若是沒有開發環境,直接用 debugbuild.bat 也就能夠直接編譯。另外還能夠直接運行測試 r6rstest.batlinux
在網站上下載IronScheme的應用程序後,能夠直接看到它已經提供了不一樣環境下的控制檯程序,分別有64位與32位,.NET 2.0與4.0的程序: IronScheme.Console32-v2.exe IronScheme.Console32-v4.exe IronScheme.Console-v2.exe IronScheme.Console-v4.exesql
找一個合適的控制檯運行下,輸入幾個Lisp表達式看看: 編程
Lisp程序有一個自然的執行多個參數運算的特色,因此咱們能夠執行多個數字相加。也可使用 display 函數顯示一個字符串。架構
寫一個簡單的Hello 程序文件來加載 試試:框架
執行這個程序,成功 ,可是亂碼,不論是存儲成 ANSI格式仍是UTF8格式均亂碼:函數
無奈,只有打開IronScheme源碼進行分析,分析了好久好久....學習
最後乾脆直接搜索編碼格式 Encoding...,好歹涉及這個關鍵詞的地方只有3個:測試
在 IronScheme.Console 項目下的 Program 文件中,找到下面的代碼:字體
Encoding oo = Console.OutputEncoding; EnableMulticoreJIT(); try { //Console.OutputEncoding = Encoding.UTF8; return IronSchemeConsoleHost.Execute(args); } finally { Console.OutputEncoding = oo; }
將原來的 Console.OutputEncoding = Encoding.UTF8 註釋便可,因爲個人電腦是中文環境,這樣程序便以GBK的編碼運行了,此時便可正常顯示Scheme 程序中的 漢字。可是,若是要加載的文件名有漢字,則悲劇了,控制檯沒法輸入漢字...
再次檢查程序中全部跟控制檯有關的編碼的地方,發現除了前面檢查過的編碼問題,再也沒有其它地方,最後跟蹤調試代碼,發現程序使用
Console.ReadKey()
方法來獲取屏幕輸入的,而這個方法,是沒法得到中文輸入的...%&*....
既然是截獲了鍵盤敲擊,那麼我就頂一個特殊的鍵,按下它在彈窗出來一個窗口,在裏面輸入中文就能夠了吧,因而找到文件 SuperConsole.cs ,找到 Insert(ConsoleKeyInfo key) 方法,修改爲下面的代碼:
private void Insert(ConsoleKeyInfo key) { char c; if (key.Key == ConsoleKey.F6) { Debug.Assert(FinalLineText.Length == 1); c = FinalLineText[0]; } else if (key.Modifiers == ConsoleModifiers.Alt && (key.Key >= ConsoleKey.NumPad0 && key.Key <= ConsoleKey.NumPad9)) { c = '?'; } else { c = key.KeyChar; } //Ctrl+Z 輸入漢字 if (key.Key == ConsoleKey.Z && key.Modifiers == ConsoleModifiers.Control) { frmInputString frm = new frmInputString(); frm.Activate(); frm.ShowDialog(); //Console.Write(frm.Text); string s = frm.Text; _input.Append(s); Output.Write(s); _rendered += s.Length; _current += s.Length; } else { Insert(c); } }
這樣就能夠在Scheme控制檯彈窗輸入中文了,順便加入文件選擇功能,方便加載程序文件,如圖:
控制檯默認的字體是 「點陣字體」,這種字體在輸入中文後,Scheme 定位字符位置會有問題,應該使用非點陣字體,例如以下圖的設置(控制檯窗口標題--屬性--字體):
按照 做者官方的說法,IronScheme是能夠簽入在.NET應用程序裏面的,可是單獨執行Scheme程序的時候,是否能夠調用 .net已有的程序呢?這個IronScheme也提供了,下面是 https://ironscheme.codeplex.com/wikipage?title=clr-syntax&referringTitle=Documentation 頁面的內容:
These macro's are exported from the (ironscheme clr) library.
type is either:
(clr-namespaces) Returns all the imported at the lexical scope
(clr-reference reference) reference can be a symbol for the assembly short name (ie System.Web) or a string containing the fully qualified assembly name.
(clr-using namespace) namespace is a symbol. Eg System.IO .
(clr-call type method instance arg ...) method is a symbol for a simple name, eg ToInt32 or a string to resolve specific methods, eg "ToInt32(Object)" . instance is a reference to the object of type . Can be null ('()) for static methods. arg ... is the arguments passed to the method.
(clr-cast type expr) expr is the instance to be cast.
(clr-is type expr) expr is the instance to be tested.
(clr-new type arg ...) arg ... is the arguments passed to the constructor.
(clr-new-array type size) size is the size of the array. Must be an integer.
(clr-event-add! type event instance handler) event is a symbol for the name of the event. Eg Click . instance is a reference to the object of type . Can be null ('()) for static events. handler is a procedure taking the same number of arguments as the event's delegate.
(clr-event-remove! type event instance handler) event is a symbol for the name of the event. Eg Click . instance is a reference to the object of type . Can be null ('()) for static events. handler is a procedure taking the same number of arguments as the event's delegate.
(clr-field-get type field instance) field is a symbol for the name of the field. Eg m_foo . instance is a reference to the object of type . Can be null ('()) for static fields.
(clr-field-set! type field instance expr) field is a symbol for the name of the field. Eg m_foo . instance is a reference to the object of type . Can be null ('()) for static fields. expr is the value to set the field.
(pinvoke-call library method arg ...) arg ... is the arguments passed to the method.
(clr-indexer-get type instance arg ...) instance is a reference to the object of type . arg ... is the arguments passed to the indexer.
(clr-indexer-set! type instance arg ... expr) instance is a reference to the object of type . arg ... is the arguments passed to the indexer. expr is the value to set the indexer.
(clr-prop-get type property instance) property is the name of the property. Eg Height . instance is a reference to the object of type . Can be null ('()) for static properties.
(clr-prop-set! type property instance expr) property is the name of the property. Eg Height . instance is a reference to the object of type . Can be null ('()) for static properties. expr is the value to set the property.
(clr-static-call type method arg ...) method is a symbol for a simple name, eg ToInt32 or a string to resolve specific methods, eg "ToInt32(Object)" . arg ... is the arguments passed to the method.
(clr-static-event-add! type event handler) event is a symbol for the name of the event. Eg Click . handler is a procedure taking the same number of arguments as the event's delegate.
(clr-static-event-remove! type event handler) event is a symbol for the name of the event. Eg Click . handler is a procedure taking the same number of arguments as the event's delegate.
(clr-static-field-get type field) field is a symbol for the name of the field. Eg m_foo .
(clr-static-field-set! type field expr) field is a symbol for the name of the field. Eg m_foo . expr is the value to set the field.
(clr-static-prop-get type property) property is the name of the property. Eg Height .
(clr-static-prop-set! type property expr) property is the name of the property. Eg Height . expr is the value to set the property.
看來支持得還挺全面,立刻寫個程序試試看:
(import (rnrs) (ironscheme clr)) ;Define a function write-ln (define (write-ln fmt . args) (clr-static-call System.Console WriteLine (clr-cast System.String fmt) (clr-cast System.Object[] (list->vector args)))) ; And invoke it! (write-ln "{0}" "Hello World!") (write-ln "1:{0}" "aaa") (write-ln "1:{0} 2:{1}" "張三" "李四")
這個程序是調用 .net的 Console.WriteLine 方法的,運行這個程序試試:
注意程序文件須要保存爲 UTF8格式的,IronScheme 才能夠正常顯示中文。
利用 Lisp的強大表達能力,調用.net強大的類庫
Scheme能夠看成腳本語言,能夠.net程序動態生成一個 Scheme程序,Scheme程序再調用.net。。。。 這個過程的用途,明白了吧?
好比工做流程序,調用一個Scheme 腳本..
更多的 Lisp,Scheme學習資源,能夠參考下面的連接 :
Lisp 的永恆之道
http://www.oschina.net/question/28_57183
Scheme語言--簡介
http://blog.csdn.net/zzulp/article/details/5547729
學習Scheme
http://blog.csdn.net/ramacess/article/details/570769
Scheme 語言概要
http://www.ibm.com/developerworks/cn/linux/l-schm/index1.html
Read access to a .NET Assembly
https://ironscheme.codeplex.com/discussions/60977
Playing with IronScheme
http://www.codeproject.com/Articles/33050/Playing-with-IronScheme
尾遞歸
http://blog.sina.com.cn/s/blog_3e5694650100tzqq.html
本文程序下載 「IronScheme中文版」
http://pwmis.codeplex.com/releases/view/117822
---------分界線 ----------------
歡迎使用 PDF.NET SOD 開源框架,框架追求的目標是簡單與效率的平衡,體如今:代碼的精簡,開發、維護的簡單與追求極致的運行效率。
做者簡介:
本人現任職架構師,求伯樂,聯繫方式:http://www.pwmis.com/sqlmap