拿 C# 搞函数式编程 - 1
最近闲下来了,准备出一个 C# 搞 FP 的合集。本合集所有代码均以 C# 8 为示例。
可能你说,为什么要这么做呢?回答:为了好玩。另外,意义党们请 gun cu ke!
C# 有委托,而且有 Func<> 和 Action<>,可以说函数被视为一等功名,跟 int、bool 等类型并没有什么区别。那么很多事情就简单了。
纯函数
什么是纯函数呢?纯函数就是 f(x),它们接收参数,得到结果,并且相同的参数得到的结果一定是相同的,用映射来说,它是满射的。另外这个函数不会改变任何的状态值,它是无副作用的。
柯里化
首先,有一个东西让我觉得不爽,那就是一般来说 C# 里的函数调用不是柯里化的,这也就意味着我没法一个一个传参数进去,也没法把传了一部分参数的调用作为一个新函数拿去给别的地方用,那要怎么办呢?
自己动手,丰衣足食!
一个标准的加法函数可以这么写:
var function = new Func<int, int, int> ((x, y) => x + y); function(1, 2); // returns 3
如果我们想以柯里化形式调用的话,理想状态是这么个样子的:
function 1 2
但是这个括号我们是省不了的,所以这样也是可以接受的:
function(1)(2);
我们看一下这个调用形式,不就是 Func<int, Func<int, int>> 嘛!so easy~
我们只需要把 Func<int, int, int> 转化为 Func<int, Func<int, int>>:
Func<int, Func<int, int>> Currying(Func<int, int, int> f) => x => y => f(x, y);
这样写就 ok 啦。进一步改造成扩展方法:
public static class CurryingExtensions { public static Func<int, Func<int, int>> Currying(this Func<int, int, int> f) => x => y => f(x, y); }
于是我们只需要:
var function = new Func<int, int, int> ((x, y) => x + y) .Currying(); function(1)(2); // returns 3
就可以采用柯里化形式调用该函数啦。
进一步我们用泛型改造,让柯里化适用于任何类型:
public static class CurryingExtensions { public static Func<T1, Func<T2, TOutput>> Currying<T1, T2, TOutput>(this Func<T1, T2, TOuput> f) => x => y => f(x, y); }