函数式编程学习之路(五)
荆棘:
刚开个头,身体就出点小毛病,这充分说明,这玩意必须吃透不可,遇到困难就放弃,那么以后可能也没办法再提高了.
零零碎碎查不少资料,泛泛看了些东西,先记下来.
首先,传统C#是没有闭包的.但有了匿名函数和Lambda后,就有了这个东东.
public class TCloser { public Func<int> T1() { var n = 999; return () => { Console.WriteLine(n); return n; }; } } class Program { static void Main() { var a = new TCloser(); var b = a.T1(); Console.WriteLine(b()); } }
C#再通过委托(直接用不方便),加泛型,定义了Func<T, TRusult> 这的东西, 间接的完成了函数传入及返回.
最后通过Lambda表达式,实现了函数式编程所需要的基本东西.
当然,C#是强类型的,所以为了达成目的又加了些东西,C#4.0加入了in(逆变), out(协变),当然了字面意思,文档,教科书等都把这种简单思想搞太复杂.好在本人懂面向对象啊.也懂点什么叫强类型.具不想用弱类型,又想实现类型推导.
逆变允许方法具有与接口的泛型形参所指定的实参类型相比,派生程度更小的实参类型。
协变允许方法具有与接口的泛型类型参数所定义的返回类型相比,派生程度更大的返回类型。
说穿了,就是为了隐式转换,作为参数,我们假想下,底层编译成IL时,根据定义,去查找定义的类型,in一般作为参数修饰 找最顶层的,比如object, 这样什么参都可以传入, out找最底层的.这样返回的变量,很容易匹配 ,比如object = out TResult
还是那句老话,简单的东西,搞这么复杂,MS的这些人,过犹不及, 在这种地方不用弱类型,目的无非是在VS编辑器里可以. 出来.让用户更傻瓜化,花更多的钱去买,然后使用更人工复杂化的东西.天下没有免费的午餐,不迷信权威,是提高的不二途径.
Y组合子:
static Func<T, TResult> Fix<T, TResult>(Func<Func<T, TResult>, Func<T, TResult>> f) { return x => f(Fix(f))(x); } static Func<T1, T2, TResult> Fix<T1, T2, TResult>(Func<Func<T1, T2, TResult>, Func<T1, T2, TResult>> f) { return (x, y) => f(Fix(f))(x, y); }
有了泛型,Func, in, out, Y组合子也有了.看上去C#函数式编程问题不大了(可能不够直观,但起码可用)
再来点简单直观的
Func<int, int> fun = (int x) => x * x;
算是有个fun的变量(或函数符号)了,因为函数式编程,是没有变量,没有副作用的.
通过这里我们可以看到,fun是个函数,或一个算法,本身是个概念,或者一个规则,这里的规则,就是完成乘这个概念.
最后,当我们把大量的东西概念化(函数化)后,我们得到了大量不可变的概念,规则.这就是所谓的"声明式编程".
Func<int, int, int> addition = (int x, int y) => x + y;
Func<int, int, int> subtraction = (int x, int y) => x - y;
Func<int, int, int> multiplication = (int x, int y) => x * y;
//计算 x = 1 + 2 * (3 - 1)
int result = addition(1, multiplication(2, subtraction(3, 1)));
看上去还不错,但这个玩意和传统函数调用没两样,还需要具体深入.
看着就不象函数式编程.