C#函数式编程之部分应用
何谓函数式编程
相信大家在实际的开发中,很多情况下完成一个功能都需要借助多个类,那么我们这里的基本单元就是类。而函数式编程则更加细化,致使我们解决一个功能的基本单元是函数,而不是类,每个功能都是由多个函数构成,并且函数之间没有直接的关系。如果简单的文字描述还不足以让你理解,下面我们就配以图来演示。
如下图所示,图左是我们设计好的三个函数,而右边则是我们需要实现的功能。而我们需要做的就是利用这三个函数去完成对应的三个功能,笔者在这里只是进行简单而又形象的表述,实际的开发过程可能需要更多的函数,并且需要使用不同的函数式编程的方式组合才能完成对应的功能。

后面我们假设F1和F2进行组合可以完成功能G1,那么结果就如下图所示:

对应的其他功能我们依然是按照上面的方式进行组合就可以完成对应的功能,这样做必然有其对应的优点,对笔者而言最大的优点就是函数不受外部环境的影响,这里我们不能与类中的方法相提并论,因为方法会受到类上下文变量的影响,特别是在多线程的情况下会出现共享读和写的问题,而函数则不会,因为他只是通过参数的方式接收外部的变量,还有一点就是复用性很强,如果前期设计的充分,在后期开发过程中函数可以发挥到最大的作用。说了这么多废话,下面我们就可以开始我们的函数式编程的第一部分——部分应用。
部分应用
各位不用被这个名词吓坏,他主要是将我们多个参数的函数进行拆分,拆成多个只有一个参数的函数,比如下面这个函数,我们正常写的话都是这样写的:
Func<int, int, int> Add = (x, y) => x + y;
怎么调用相信笔者就不需要过多介绍了,下面我们就要让他能够支持部分应用:
Func<int, Func<int, int>> Add = x => y => x + y;
这下就应该明白了吧,只是在接收了一个值之后返回了下一个函数,然后我们再调用这个返回的函数就完成整个调用,我们是不是部分使用了这个函数?所以叫部分应用。下面我们来看看怎么使用这个函数:
var Add2 = Add();
var result = Add2();
这样分成两行比较容易看懂,但是我们可以仅仅使用一行就可以了,比如下面这个方式:
var result = Add()();
哇,是不是瞬间感觉高大上了,如果我们这个方法的参数再多点,就是括号加括号,相信别人看到你这行代码后就会呵呵了,然后心里一万个“某某”马奔腾。
我去,看到这的人会可能会吹嘘这又没有什么太特别的东西,就是函数返回函数。对就是函数返回函数,但是实际运用起来你就会发现舒畅多了,下面笔者简单的举一个比较靠谱的例子来说明部分应用能够带给我们什么,比如我们经常需要执行SQL语句,当然需要使用SqlConnection,然后附加上对应的SQL语句,为此我们可以开发一个简单的函数,用来简化这一过程:
Func<SqlConnection, Func<String, DataSet>> ExecSql = x => y =>
{
using (x)
{
x.Open();
var com = x.CreateCommand();
DataSet ds = new DataSet();
com.CommandText = y;
SqlDataAdapter adapter = new SqlDataAdapter(com);
adapter.Fill(ds);
return ds;
}
};
然后调用起来就简单多了,我们只要传递给对应的SqlConnection对象,然后对应的返回值我们就可以用来执行我们的SQL语句了,具体的使用示例如下所示:
var esql = ExecSql(new SqlConnection("xxx"));
var rds = esql("select xxxx from xxx");
rds = esql("select ffff from ffff");
但是做到这还没有结束,面对那些总是想出奇怪问题的人,我们还有一个需要做,就是我们可能先要传递SQL语句,然后再传递对应的SqlConnection对象,没问题,我们专门为此写个函数:
Func<String, Func<SqlConnection, DataSet>> ExecSqlT = x => y => ExecSql(y)(x);
我们就继续该怎么调用就调用吧,但是上面都是从一开始就利用部分应用的方式来写,实际情况可能是已经写好的普通的方式,需要转换成部分应用的方式。那么下面我们可以自己先手动的写几个扩展,以便于以后的使用,首先我们来写存在两个参数和返回值的扩展:
public static class Functional
{
public static Func<T1, Func<T2, T3>> Currey<T1, T2, T3>(this Func<T1, T2, T3> func)
{
return x => y => func(x, y);
}
}
有了这个扩展之后我们再把上面的例子改写:
var ExecSql = Functional.Currey<SqlConnection, String, DataSet>((x, y) =>
{
using (x)
{
x.Open();
var com = x.CreateCommand();
DataSet ds = new DataSet();
com.CommandText = y;
SqlDataAdapter adapter = new SqlDataAdapter(com);
adapter.Fill(ds);
return ds;
}
});
这样我们就可以按照我们正常的形式来写,然后调用Functional的Currey就可以了,当然这里需要显示的传递泛型参数,有些情况下则不需要。
如果需要扩展更多参数的可以对应的写下去就可以了。当然上面仅仅只是针对没有参数的情况,我们也可以对Action也进行扩展:
public static Func<T1, Action<T2>> Currey<T1, T2>(this Action<T1, T2> func)
{
return x => y => func(x, y);
}
到此我们就解决了将普通函数转换成部分应用方式的函数,但是问题就来了。如果我们一开始写的是部分应用方式的函数,怎么将其转换成普通的函数呢?自然我们还需要下面的扩展能够将其转换回去:
public static Func<T1, T2, T3> UnCurrey<T1, T2, T3>(this Func<T1, Func<T2, T3>> func)
{
return (x, y) => func(x)(y);
}
C#函数式编程之部分应用的更多相关文章
- angular2系列教程(六)两种pipe:函数式编程与面向对象编程
今天,我们要讲的是angualr2的pipe这个知识点. 例子
- [学习笔记]JavaScript之函数式编程
欢迎指导与讨论:) 前言 函数式编程能使我们的代码结构变得简洁,让代码更接近于自然语言,易于理解. 一.减少不必要的函数嵌套代码 (1)当存在函数嵌套时,若内层函数的参数与外层函数的参数一致时,可以这 ...
- 函数式编程之柯里化(curry)
函数式编程curry的概念: 只传递给函数一部分参数来调用函数,然后返回一个函数去处理剩下的参数. var add = function(x) { return function(y) { retur ...
- 关于Java8函数式编程你需要了解的几点
函数式编程与面向对象的设计方法在思路和手段上都各有千秋,在这里,我将简要介绍一下函数式编程与面向对象相比的一些特点和差异. 函数作为一等公民 在理解函数作为一等公民这句话时,让我们先来看一下一种非常常 ...
- Haskell 函数式编程快速入门【草】
什么是函数式编程 用常规编程语言中的函数指针.委托和Lambda表达式等概念来帮助理解(其实函数式编程就是Lambda演算延伸而来的编程范式). 函数式编程中函数可以被非常容易的定义和传递. Hask ...
- java1.8函数式编程概念
有关函数式编程 ·1 函数作为一等公民 特点:将函数作为参数传递给另外一个函数:函数可以作为另外一个函数的返回值 ·2 无副作用 函数的副作用指的是函数在调用过程中,除了给出了返回值外,还修改了函数外 ...
- 让JavaScript回归函数式编程的本质
JavaScript是一门被误会最深的语言,这话一点不假,我们看下它的发展历史. 1995年,Netscape要推向市场,需要一门脚本语言来配套它.是使用一门已有的语言,还是发明一门新的语言,这也不是 ...
- python基础-函数式编程
python基础-函数式编程 高阶函数:map , reduce ,filter,sorted 匿名函数: lambda 1.1函数式编程 面向过程编程:我们通过把大段代码拆成函数,通过一层一层 ...
- python函数 与 函数式编程
「函数」一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,具体区别,我们后面会讲,编程中的函数在英文中也有很多不同的叫法.在BASIC中叫做subroutine(子过程或子程序), ...
- Reactor事件驱动的两种设计实现:面向对象 VS 函数式编程
Reactor事件驱动的两种设计实现:面向对象 VS 函数式编程 这里的函数式编程的设计以muduo为例进行对比说明: Reactor实现架构对比 面向对象的设计类图如下: 函数式编程以muduo为例 ...
随机推荐
- SQL笔记-第五章,函数
一.数学函数 功能 函数名 用法 绝对值 ABS() 指数 POWER() POWER(FWeight,-0.5) 平方根 SQRT() 求随机数 RAND() 舍入到最 ...
- JAVA的Random类[转]
在实际的项目开发过程中,经常需要产生一些随机数值,例如网站登录中的校验数字等,或者需要以一定的几率实现某种效果,例如游戏程序中的物品掉落等. 在Java API中,在java.util包中专门提供了一 ...
- Python字典方法总结
1.清空字典中元素清空,dict变为{} L.clear()-> None. Remove all items from L 1 2 3 4 >>> L ={'shaw':2 ...
- VC++ 在两个程序中 传递字符串等常量值的方法:使用了 WM_COPYDATA 消息的
消息作用: 在进程间共享数据(内部通过创建内存映射文件) 消息介绍:需要用到的数据结构/类型:typedef struct tagCOPYDATASTRUCT { ULONG_PTR dw ...
- oracle根据分隔符将字符串分割成数组函数
--创建表类型 create or replace type mytype as table of number;--如果定义成varchar--CREATE OR REPLACE type myty ...
- bind的用处
刚做的项目,遇到过这样的问题,就是在动态追加标签时,给追加的标签添加事件时,在标签内追加不了,后来使用了delegate代理,能响应了,但也是不能给动态追加的代理 $("body" ...
- 计算机病毒实践汇总四:netcat使用方法
在尝试学习分析的过程中,判断结论不一定准确,只是一些我自己的思考和探索.敬请批评指正! 1. netcat概述 (1)特性 "TCP/IP协议栈瑞士军刀",可以被用在支持端口扫描. ...
- 先进先出集合queue
先进先出集合queue Enqueue添加到集合最后 Dequeue移除集合第一个对象并返回
- 以前编写的inno setup脚本,涵盖了自定义安装界面,调用dll等等应用 (转)
以前编写的inno setup脚本,涵盖了自定义安装界面,调用dll等等应用 (转) ; Script generated by the Inno Setup 脚本向导. ; SEE THE DOCU ...
- MVC concept
What are MVP and MVC and what is the difference? http://stackoverflow.com/questions/2056/what-are-mv ...