函数式编程Functional Programming
FP是一种将计算是为对表达式求值的编程范式
FP优点
- 可组合性和模块化
- 表达性
- 可靠性和测试
- 易于并发
- 延迟求值
- 生产力
- 正确性
- 可维护性
FP原则
- 高阶函数(HOF)作为头等值
- 不可变性
- 纯函数
- 声明式编程风格
HOF
FP中函数作为头等值,意味着函数可以由变量命名、分配给变量,可以出现在任何构造可以出现的地方。
HOF使编程专注于结果,而不是步骤。
HOF优点
- 组合和模块化
- 实现函数式组合的方式
- 组合
- 柯里化
- 部分应用函数
- 实现函数式组合的方式
- 代码可重用性
- 创建高度动态和适应性强的系统
HOF与lambda
一种重构代码,减少代码冗余的方式,一个优雅的解决方案。
- 简洁的内联编码
- 限制类级别变量的暴露
- 代码流易读性高
Example:
- stream在使用后被Disposed,一种不可重复使用的模式。
string text;
using(var stream = new StreamReader(path))
{
text = stream.ReadToEnd();
}
- 灵活、可重用的清理一次性资源的方式。
public static R Using<T,R>(this T item,Func<T,R> func) where T:IDisposable
{
using(item)
{
return func(R);
}
}
string text = new new StreamReader(path).Using(s => s.ReadToEnd);
Currying
- 每个函数只具有一个参数
- 专用函数更易于重用
- 多个参数的函数将转换成函数序列的求值,即生成函数链
C#中的Curry & UnCurry
pubilc static Func<T,Func<R,S>> Curry<T,R,S>(this Func<T,R,S> func)
{
return t => r => func(t,r);
}
pubilc static Func<T,R,S> UnCurry<T,R,S>(this Func<T,Func<R,S>> func)
{
return (x,y) => func(x)(y);
}
部分应用函数
将多个参数固定到一个函数并生成参数更少的函数
public static Func<T,S> Partial<T,R,S>(this Func<T,R,S> func,T arg)
{
return arg2 => func(arg,arg2);
}
Currying & 部分应用函数
Example:
一个通用的Retry方法里,
public static T Retry<T>(Func<T> func){...}
无法适用于带参数的情况,重写一个新版本的带有参数的的Retry函数并不是一个理想的选择,因为每个方法的参数个数可能不一致,为每种情况重写一个方法十分不优雅。
更好的选择是使用部分应用函数和Curry方法:
public static Func<R> Partial<T,R>(this Func<T,R> func,T arg)
{
return () => func(arg);
}
public static Func<T,Func<R>> Currying<T,R>(this Func<T,R> func)
{
return arg => func(arg);
}
Func<string,string> readText = (path) => ReadText(path);
string text = readText.Partial(path).Retry();
Func<string,Func<string>> curryRead = readText.Curry();
string text = curryRead(path).Retry();