我发现尽管我进了最大的努力来解释(中文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