C#中的程式碼和資料
我發現儘管我進了最大的努力來解釋(中文blog鏈節),還是有不少傢伙還是不知道LINQ是如何工作的。
那麼這回讓我再試一次,速度稍慢一點,解剖一個簡單的程式,來詳細的講解在Scheme 和C#3.0中的 code == data 主題。
// Line 1: (define f (lambda (a) (+ a 1)))
Func f = a => a + 1;
// Line 2: (define e (quote (lambda (a) (+ a 1))))
Expression> e = a => a + 1;
// Line 3: (define elong (list 'lambda (list 'a ) (list '+ 'a 1 )))
ParameterExpression ap = Expression.Parameter(typeof(int), "a");
Expression> elong =
Expression.Lambda>(
Expression.Add(ap, Expression.Constant(1)),
ap);
// Line 4: (display (car (car (cddr e)))) ; prints +
Console.WriteLine(e.Body.NodeType); // prints Add
// Line 5:(display (elong 4)) ; runtime error: procedure application: expected procedure, given: (lambda (a) (+ a 1))
Console.WriteLine(elong(4)); // compile-time error CS0118: 'elong' is a 'variable' but is used like a 'method'
// Line 6: (define f2 (eval elong (scheme-report-environment 5)))
Func f2 = elong.Compile();
// Line 7: (display (f2 4)) ; prints 5
Console.WriteLine(f2(4)); // prints 5
其中Line1和Line2是最重要的。
無論在Lisp/Scheme和C#3.0中,都沒有引號機制來區分前端和末端,進而不能將表示式識別為資料,並且也不能將其轉換不透明的,但仍然可以直接執行的函式。
在Lisp/Scheme中,我們用引號的特殊形式來關閉解析器。這個特殊引用形式如我先前貼上的那樣簡短,帶有(')號。
在C#中,編譯器在出現Lambda 表示式的地方尋找上下文關係。如果它被賦值了一個委託型別(形如Func),編譯器就會像在C#2.0中那樣,產生一個不透明的基於IL的方法。如果它在TSignature是一個委託型別的地方被賦值為表示式,它會生成一個表示式樹,這個樹等同於我稍後手工建立並將其賦值給變數elong的程式碼(參見Line3)。完整的說,我是以一種更加冗餘的方式,展示如何用Scheme的列表函式做等同於列表建立的方法(我相信如果我一步一步地寫完所有的程式碼,人們一定會嚇壞的)。
注意,在程式碼的Line4部分,為了翻譯結構資料,我們可以用標準機制來提取表示式中的任何一部分。在Scheme版中,我使用了列表析構操作符car 和 cddr。在C#版中,我使用了帶名稱的屬性機制(LINQ表示式以帶名稱的屬性型別構成,而不是簡單的列表)。無論在C#版還是在Scheme版中,e和elong的值都是互等的。
Line5這行程式碼絆倒了不少學習Lisp或Scheme(或LINQ)的人。
當你引用表示式時,你會捲起單純的舊資料,將其切片和切丁成你所希望的。而你不能直接對資料做的是直接執行它。因此,Line 5 在C#編譯時和在Scheme執行時,都會報錯。
要把資料翻譯成你可以執行的東西,不論是Lisp/Scheme和C#,都要求你顯示地寫一段程式碼(見Line 6)。在Scheme中,這段程式碼是Lambda解析的特殊形式,它將餘下的列表翻譯可執行的東西(R5RS-speak中的過程物件)。在LINQ中,這段程式碼呼叫了Lambda表示式上的Compile()方法。這兩中操作都產生了一個不透明的,隨時可用於執行的值。有了這個不透明的可執行值,我們就可以得到Line 7,列印輸出我們心愛的"5"。
Patrick和James Robertson都提到,這些東西讓我們正輕率地回到了過去。
要是我能禱告將這些東西分解/還原,使這個產業退回到80年代後期和90年代就好了,但是我不能呀!
我能說的只是我和my friend the token Smalltalk weenie 焦急地等待著過去,並正盡我們所能來實現它。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1441470
相關文章
- C#中的資料結構C#資料結構
- 初探資料庫通用程式碼庫的封裝(C#版)資料庫封裝C#
- c#複製包含子目錄資料夾程式碼C#
- C# 從程式碼入門 Mysql 資料庫事務C#MySql資料庫
- oracle中利用資料字典生成程式碼Oracle
- 【轉】[C#] 1行程式碼實現C#複製資料夾功能C#行程
- java開發中JDBC連線資料庫程式碼和步驟JavaJDBC資料庫
- C#中處理JSON資料的方式C#JSON
- 完整java開發中JDBC連線資料庫程式碼和步驟JavaJDBC資料庫
- 資料結構中的線性表程式碼實現資料結構
- C# 程式開發中經常遇到的10條實用的程式碼C#
- C#程式開發中經常遇到的10條實用的程式碼C#
- SQL資料型別和C#資料型別間的轉換SQL資料型別C#
- C# 中的INotifyPropertyChanged和ObservableCollectionC#
- C#中?和??及?:的用法C#
- 重學c#系列——c# 託管和非託管資源與程式碼相關(四)C#
- C#連線和操作Oracle資料C#Oracle
- 機器學習中的模型和資料機器學習模型
- 常用的資料庫程式碼資料庫
- 將sql中的money轉化為c#中的資料型別SQLC#資料型別
- C# 讀取Word文字框中的文字、圖片和表格(附VB.NET程式碼)C#
- 提高 Unity 中 C# 程式碼質量的 21 條準則UnityC#
- 程式碼換膚術(一)——C#和VB (轉)C#
- 一段後臺C#查詢SQL Server資料庫程式碼C#SQLServer資料庫
- js實現的查詢表格中的資料程式碼例項JS
- 將連線資料庫的程式碼隱藏在DLL中(轉)資料庫
- C# 移除陣列中重複資料C#陣列
- C# datatable中重複資料去重C#
- c#資料操作:資料庫訪問 和 檔案操作C#資料庫
- Java 中的資料流和函數語言程式設計Java函數程式設計
- JavaScript 的資料結構和演算法 - 棧程式碼篇JavaScript資料結構演算法
- C#中從Clipboard儲存獲取資料的方法C#
- C#中的Unsafe和FixedC#
- C# 中的委託和事件C#事件
- 編寫更好的C#程式碼C#
- 集合資料處理(C#、JavaScript 和 Java)C#JavaScript
- 程式碼生成器Sql Server 和 Mysql 資料庫指令碼ServerMySql資料庫指令碼
- CRS bin資料夾中的程式