函数式编程中比较有代表性的特点如:高阶函数(函数做为函数的参数),组合函数,纯函数缓存等。
F#就是一门函数式编程语言,但是C#是一门指令性的语言,并不包含全部函数式编程的全部特征。
用C#实现函数式编程,利用到了C#各种新增特性,如lambda表达式、表达式树、LINQ、扩展方法等等。
因此这个话题一方面是深入理解C#语言的一个途径,另一方面来说,一种新的编程模式本身就是非常有趣也有能吊起人味口的东西,因此,当年函数式编程也让勇哥痴迷了一把。
下面我把当初学习时的实验代码发上来,这些实验代码只包含了部分函数编程的知识,当年勇哥也是学到半途而废了呀,汗!
如果有可能,勇哥也想把函数式编程继续研究下去,我感觉它很酷!
实际上当年我是把它和设计模式并列为一种东西看待的。用得好,都能即艺术化自己的代码,又能得到实际的好处。

代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FCSlib;
using System.Data.SqlClient;
using System.Data;
namespace ConsoleApplication1
{
static class helpmethod
{
public static Func<T1, Func<T2, TR>> curry<T1, T2, TR>(this Func<T1, T2, TR> func)
{
return p1 => p2 => func(p1, p2);
}
}
class Program
{
#region 函数式编程实例:执行SQL代码
static void ExecuteSQL(SqlTransaction transaction, string sql)
{
var command = transaction.Connection.CreateCommand();
command.Transaction = transaction;
command.CommandText = sql;
command.ExecuteNonQuery();
}
static void filldata1()
{
//下面的代码是需要重构的原始代码
using (var conn = new SqlConnection("server=(local);integrated security=SSPI;database=sanyopg"))
{
conn.Open();
try
{
using (var trans = conn.BeginTransaction())
{
ExecuteSQL(trans, "create table people(id int,name ntext)");
trans.Commit();
}
using (var trans = conn.BeginTransaction())
{
ExecuteSQL(trans, "insert into people(id,name) values(1,'harry')");
ExecuteSQL(trans, "insert into people(id,name) values(2,'jane')");
ExecuteSQL(trans, "insert into people(id,name) values(3,'willy')");
ExecuteSQL(trans, "insert into people(id,name) values(4,'susan')");
ExecuteSQL(trans, "insert into people(id,name) values(5,'bill')");
ExecuteSQL(trans, "insert into people(id,name) values(6,'jennifer')");
ExecuteSQL(trans, "insert into people(id,name) values(7,'john')");
ExecuteSQL(trans, "insert into people(id,name) values(8,'anna')");
ExecuteSQL(trans, "insert into people(id,name) values(9,'bob')");
ExecuteSQL(trans, "insert into people(id,name) values(10,'mary')");
trans.Commit();
}
}
finally
{
conn.Close();
}
}
}
static void filldata2()
{
//下面使用Lambda表达式重构
//变化:模块化发生在函数级,实现重用,但是修改没有扩展到外层的作用域,外层没有受到这个修改的“污染”
using (var conn = new SqlConnection("server=(local);integrated security=SSPI;database=sanyopg"))
{
conn.Open();
try
{
using (var trans = conn.BeginTransaction())
{
ExecuteSQL(trans, "create table people(id int,name ntext)");
trans.Commit();
}
using (var trans = conn.BeginTransaction())
{
Action<SqlTransaction,int,string> exec=(t,id,name)=>
ExecuteSQL(t,string.Format("insert into people(id,name) values({0},'{1}')",id,name));
exec(trans, 1, "harry");
exec(trans, 2, "jane");
exec(trans, 3, "willy");
exec(trans, 4, "susan");
exec(trans, 5, "bill");
exec(trans, 6, "jennifer");
exec(trans, 7, "john");
exec(trans, 8, "anna");
exec(trans, 9, "bob");
exec(trans, 10, "mary");
trans.Commit();
}
}
finally
{
conn.Close();
}
}
}
static void filldata3()
{
//使用部分应用和预计算重构
//filldata2()的实现,在每一行都接受trans参数。因此可以想到用部分应用和预计算进行重构
using (var conn = new SqlConnection("server=(local);integrated security=SSPI;database=sanyopg"))
{
conn.Open();
try
{
using (var trans = conn.BeginTransaction())
{
ExecuteSQL(trans, "create table people(id int,name ntext)");
trans.Commit();
}
using (var trans = conn.BeginTransaction())
{
var sql="insert into people(IDataAdapter,namespace) values({0},'{1}')";
var exec =(
(Func<SqlTransaction, Func<int, Action<string>>>)
(t => id => name => ExecuteSQL(t, string.Format(sql, id, name)))
)(trans);
exec(1)("harry");
exec(2)("jane");
exec(3)("willy");
exec(4)("susan");
exec(5)("bill");
exec(6)("jennifer");
exec(7)("john");
exec(8)("anna");
exec(9)("bob");
exec(10)("mary");
trans.Commit();
}
}
finally
{
conn.Close();
}
}
}
#endregion
#region 预计算
static bool IsInListDump<T>(IEnumerable<T> list, T item)
{
var hashSet = new HashSet<T>(list);
return hashSet.Contains(item);
}
static void preCal()
{
//每次都要调用一次IsInListDump函数创建哈希表,效率低下
string[] str = { "one","two","three","four","five","six","seven","eight","nine","ten" };
Console.WriteLine(IsInListDump(str,"three"));
Console.WriteLine(IsInListDump(str,"no"));
}
static void preCal1()
{
//部分应用版本,但仍然效率不好
string[] str = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
var res1 = helpmethod.curry<IEnumerable<string>, string, bool>(IsInListDump<string>);
var p1 = res1(str);
Console.WriteLine(p1("three"));
Console.WriteLine(p1("not"));
}
static Func<T, bool> listLookUp<T>(IEnumerable<T> list)
{
//hashet创建后就保存在了闭包里
var hashet = new HashSet<T>(list);
return item => hashet.Contains(item);
}
static void preCal2()
{
//实现了预计算版本
string[] str = { "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" };
var lookup = listLookUp(str);
Console.Write(lookup("three"));
Console.Write(lookup("no"));
}
#endregion
#region 缓存
#endregion
#region 闭包
static void Closures()
{
Console.WriteLine(GetClosureFunction()(30));
}
static Func<int, int> GetClosureFunction()
{
int val = 10;
Func<int, int> internalAdd = x => x + val;
Console.WriteLine(internalAdd(10));
val = 30;
Console.WriteLine(internalAdd(10));
return internalAdd;
}
#endregion
#region 部分应用
static void partApplytest1()
{
Func<int, int, int> add = delegate(int x, int y) { return x + y; };
Console.WriteLine(add(1, 2));
Func<int, Func<int, int>> add2 = delegate(int x)
{
return delegate(int y) { return x + y; };
};
Console.WriteLine(add2(1)(2));
var r1 = add2(1);
var r2 = r1(2);
Console.WriteLine(r2);
Func<int, int, int> add3 = (x, y) => x + y;
Console.WriteLine(add3(1, 4));
Func<int, Func<int, int>> add4 = x => y => x + y;
Console.WriteLine(add4(1)(4));
Func<int, int, int> add5 = (x, y) => x + y;
var f1 = Functional.Curry(add5);
Console.WriteLine(f1(1)(4));
var f2 = Functional.Curry<int, int, int>((x, y) => x + y);
Console.WriteLine(f2(1)(5));
Func<int, int, int> mult = (x, y) => x * y;
var f3 = mult.Curry();
Console.WriteLine(f3(2)(5));
Console.WriteLine(calfun.Add(2, 3));
Console.WriteLine(calfun.AddC(2)(4));
Console.WriteLine(calfun.MultC(2)(3));
}
#endregion
#region 严格求值,非严格求值,惰性求值
//C#语言小部分采用了非严格求值策略,大部分还是严格求值策略
static int DoOneThing()
{
Console.WriteLine("DoOneThing 已经求值");
return 45;
}
static void DoSomeThing(bool a, int b)
{
Console.WriteLine("DoSomeThing begin");
if (a)
Console.WriteLine("the b is {0} ", b);
Console.WriteLine("DosomeThing ok");
}
static void 非严格求值测试()
{
//由于DoOneThing()不参加计算,因此这是非严格求值的策略
bool b = true || DoOneThing() > 0;
Console.ReadKey();
}
static void 严格求值测试()
{
//由于传入的是false,所以DoOneThing()函数的值并没有被用到
//如果DoOneThing()是不个超级耗时的操作,那么就会白白浪费掉这段时间
//但这正是严格求值策略,严格求值策略的话整个表达式都会计算
DoSomeThing(false, DoOneThing());
Console.ReadKey();
}
static void DoSomeThing1(Func<bool> a, Func<int> b)
{
Console.WriteLine("DoSomeThing begin");
if(a())
Console.WriteLine("the b is {0} ", b()*b());
Console.WriteLine("DosomeThing ok");
}
static void 惰性求值1()
{
//DoSomeThing1的两个参数都是函数,这样就可以做到在需要的时候才执行
DoSomeThing1( ()=> true,()=>DoOneThing());
Console.ReadKey();
}
static void DoSomeThing2(LazyS<bool> a, LazyS<int> b)
{
Console.WriteLine("DoSomeThing begin");
if (a.Value)
Console.WriteLine("the b is {0} ", b.Value * b.Value);
Console.WriteLine("DosomeThing ok");
}
static void 惰性求值2()
{
DoSomeThing2(new LazyS<bool>(() => true),
new LazyS<int>(() => DoOneThing()));
Console.ReadKey();
}
//.net中已经为我们包含了Lazy<T>类,因此可以不使用我们自定义的LazyS类
//系统自带的Lazy功能更多,并且支持多线程
static void DoSomeThing3(System.Lazy<bool> a, System.Lazy<int> b)
{
Console.WriteLine("DoSomeThing begin");
if (a.Value)
Console.WriteLine("the b is {0} ", b.Value * b.Value);
Console.WriteLine("DosomeThing ok");
}
static void 惰性求值3()
{
DoSomeThing3(new System.Lazy<bool>(() => true),
new System.Lazy<int>(() => DoOneThing()));
Console.ReadKey();
}
#endregion
#region 预计算,缓存
static int DoSome1(int a, int b)
{
Console.WriteLine("开始计算C的值");
int c = a * a;
Console.WriteLine("结束计算C的值");
return c + b;
}
static void 不使用预计算()
{
Console.WriteLine(string.Format("C1={0},C2={1}",
DoSome1(10, 2),
DoSome1(10, 4)));
Console.ReadKey();
}
static Func<int,int> DoSome2(int a)
{
Console.WriteLine("开始计算C的值");
int c = a * a;
Console.WriteLine("结束计算C的值");
return s => c+s;
}
static void 预计算()
{
var fun1 = DoSome2(10);
Console.WriteLine(string.Format("C1={0},C2={1}",
fun1(2),
fun1(4)));
Console.ReadKey();
}
#endregion
//测试时需要自己加注释的方式一段段测试。
static void Main(string[] args)
{
不使用预计算();
预计算();
return;
惰性求值1();
惰性求值2();
惰性求值3();
return;
非严格求值测试();
Console.WriteLine("------------");
严格求值测试();
return;
//闭包
//Closures();
//Console.ReadLine();
//return;
//partApplytest1();
//预计算
//preCal();
//preCal1();
preCal2();
Console.ReadLine();
return;
//filldata2();
Console.ReadLine();
return;
Func<SqlConnection, Func<string, DataSet>> exec1 = x => y =>
{
using (x)
{
x.Open();
var com = x.CreateCommand();
var ds = new DataSet();
com.CommandText = y;
var adapter = new SqlDataAdapter(com);
adapter.Fill(ds);
return ds;
}
};
var lib = exec1(new SqlConnection("server=(local);integrated security=SSPI;database=sanyopg"));
var res1 = lib("select username from admin");
foreach (DataRow m in res1.Tables[0].Rows)
{
Console.WriteLine(m[0].ToString());
}
/*
var res2 = lib("select * from admin");
foreach (DataRow m in res2.Tables[0].Rows)
{
Console.WriteLine(m[1].ToString());
}*/
Console.ReadLine();
}
public static class calfun
{
public static int Add(int x, int y) { return x + y; }
public static readonly Func<int, Func<int, int>> AddC = Functional.Curry<int, int, int>(Add);
public static int Mult(int x, int y) { return x * y; }
public static readonly Func<int, Func<int, int>> MultC = Functional.Curry<int, int, int>(Mult);
}
public class LazyS<T>
{
T value;
Func<T> function;
bool isCreate;
public LazyS(Func<T> func)
{
function = func;
}
public T Value
{
get
{
if (!isCreate)
{
value = function();
isCreate = true;
}
return value;
}
}
}
}
}---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路


















