C# 函数式编程测试代码

函数式编程中比较有代表性的特点如:高阶函数(函数做为函数的参数),组合函数,纯函数缓存等。

F#就是一门函数式编程语言,但是C#是一门指令性的语言,并不包含全部函数式编程的全部特征。

用C#实现函数式编程,利用到了C#各种新增特性,如lambda表达式、表达式树、LINQ、扩展方法等等。

因此这个话题一方面是深入理解C#语言的一个途径,另一方面来说,一种新的编程模式本身就是非常有趣也有能吊起人味口的东西,因此,当年函数式编程也让勇哥痴迷了一把。

下面我把当初学习时的实验代码发上来,这些实验代码只包含了部分函数编程的知识,当年勇哥也是学到半途而废了呀,汗!

如果有可能,勇哥也想把函数式编程继续研究下去,我感觉它很酷!

实际上当年我是把它和设计模式并列为一种东西看待的。用得好,都能即艺术化自己的代码,又能得到实际的好处。


image.png


代码:

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
版权声明:本文为博主原创文章,转载请附上博文链接!





本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864