首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > C# >

C#函数式编程入门之Currying函数解决办法

2013-09-24 
C#函数式编程入门之Currying函数本帖最后由 caozhy 于 2013-09-17 07:40:50 编辑在函数式编程语言中,Curry

C#函数式编程入门之Currying函数
本帖最后由 caozhy 于 2013-09-17 07:40:50 编辑 在函数式编程语言中,Currying函数是一个惯用的形式。

但是对于C#程序员来说,这比较陌生。

为了解释这个问题,我们看一个小例子:

Func<int, Func<int, int>> add = x => new Func<int, int>(y => x + y);
int i = add(3)(4);
Console.WriteLine(i);


我们定义了一个函数,add,它接受一个参数,并且返回一个新的方法,接受第二个参数,并且求出最终的结果。

因此,实际上add函数本身并非一次求出最终的结果,而是分为了两步。

我们可以通过给add传递参数得到一个新的函数,然后用新的函数去求值:
Func<int, int> addTen = x => add(10)(x);
int j = addTen(i);
Console.WriteLine(j);


下面,我们用到这些预备知识实现一个复杂的,做一个通用的二元运算:
我们管这个二元运算叫做eval函数,并且带入刚才的add,实现加法运算:
Func<int, Func<Func<int, Func<int, int>>, Func<int, int>>> eval =
    x => new Func<Func<int, Func<int, int>>, Func<int, int>>(
        y => new Func<int, int>(z => y(x)(z)));
Func<int, Func<int, int>> add = x => new Func<int, int>(y => x + y);
int i = eval(3)(add)(5);
Console.WriteLine(i);

现在我们要实现减法运算,我们说了,eval是通用的二元运算,我们只要传入一个sub函数即可:
Func<int, Func<int, int>> sub = x => new Func<int, int>(y => x - y);
i = eval(i)(sub)(1);


好吧,我说的比较抽象。理论说完了,下面是实践的部分。

这个代码展示了一个遍历集合的场景:
Func<Action<int>, Action<int[]>> iter = new Func<Action<int>,Action<int[]>>
    (x => new Action<int[]>(y => { foreach (int i in y) x(i); }));
var OutputArray = iter(x => Console.WriteLine(x));
int[] data = { 1, 2, 3, 4, 5 };
OutputArray(data);

代码分为三个层次,一个是定义了一个叫iter的系统库函数,它最抽象,既没有规定遍历什么集合,也不知道遍历的过程做什么操作。
第二个是OutputArray的用户函数,这个函数规定了它的用途,用来输出元素,但是将数组作为参数。
第三个是调用OutputArray产生结果,此刻代码有了最终的用途。


[解决办法]
写法很蛋疼,看起来更蛋疼
[解决办法]
挺有意思
实验:


            Func<int, Func<int, int>> add = x => (y => x + y);
            int n = 0;
            var i = add(add(n++)(n++))(add(n++)(n++));  //6
            n = 0;
            var j = add(add(++n)(++n))(add(++n)(++n));  //10

[解决办法]
很好。
只是C#实现起来,如Func<int, Func<Func<int, Func<int, int>>, Func<int, int>>>类型看得令人郁闷;
[解决办法]
Func<int, Func<Func<int, Func<int, int>>, Func<int, int>>> eval = x => y => z => y(x)(z);


如果上面的能写成

var eval = x => y => z => y(x)(z);


该有多好;
[解决办法]
建议楼主开个F#的帖
[解决办法]
感觉不错啊,习惯lamda表达式的人就会很喜欢,例如我。
[解决办法]
感觉第一个基础例子都没看懂,是我错过了前面的教程了吗
[解决办法]
Func<int, Func<int, int>> add = delegate(int x)
                                                {
                                                    return (delegate(int y)
                                                                {


                                                                    return x + y;
                                                                });
                                                };

            Func<int, Func<Func<int, Func<int, int>>, Func<int, int>>> eval = delegate(int x)
                                                                                  {
                                                                                      return (delegate(Func<int, Func<int, int>> y)
                                                                                               {
                                                                                                   return delegate(int z)


                                                                                                           {
                                                                                                               return y(x)(z);
                                                                                                           };
                                                                                               });
                                                                                  };


这样是不是更易懂一些
[解决办法]
函数式编程,代码可读性真抽象
[解决办法]
今年新出了一本红皮书《C#函数式程序设计》;
[解决办法]
C# 的函数式编程写法太ep了,也许是先入为主的关系,Lisp风格的写法看起来比较舒服
[解决办法]
我来顶版主!顺带感谢上次在客服专区急救我的200分!!
[解决办法]
不推荐这种写法
[解决办法]
这个看起来很高级,但不太适合后来者维护阅读和理解。特别是后来者水平有限的话。
[解决办法]
在linq in action里面见过这种写法,
当时就觉得碉堡了,
using System;
using System.Collections.Generic;
using System.Diagnostics;

internal static class LanguageFeatures
{
    private static void DisplayProcesses( Func<Process , Boolean> match)
    {
        var processes = new List< Object>();
        foreach (var process in Process.GetProcesses())
        {
            if (match(process))
            {
                processes.Add( new
                                  {
                                      process.Id,
                                      Name = process.ProcessName,
                                      Memory = process.WorkingSet64
                                  });


            }
        }

        ObjectDumper.Write(processes); //打印里面的内容,别处实现的
    }

    private static void Main( string[] args)
    {
       DisplayProcesses(process => process.WorkingSet64 >= 20*1024*1024);
    }
}


因为这完全是对函数的粒度进行了重新划分,
将原来普通强类型语言的最小功能粒度--函数--进一步细化,这对于架构的设计完全是颠覆式的啊。
原来就叫做“ Currying ”么?

[解决办法]
如果从面向过程的角度来解读,肯定是很头疼的。
但如果以函数的角度来看,其实还好
比如
Func<int, Func<Func<int, Func<int, int>>, Func<int, int>>> eval =
    x => new Func<Func<int, Func<int, int>>, Func<int, int>>(
        y => new Func<int, int>(z => y(x)(z)));
Func<int, Func<int, int>> add = x => new Func<int, int>(y => x + y);
5个func依次为f1,f2,...f5.
那么就是 
f1(x)=f2
f2(f3) = f5
f3(x) = f4
f4(x) = y
f5(x) = y
其中f3 也就是代码中的y 就是一个运算规则 也就是后面的add
[解决办法]
函数式编程,代码可读性真抽象 

热点排行