C#中的程式碼和資料

gudesheng發表於2008-01-03


原文:Code and Data in 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


相關文章