C#函数式程序设计之局部套用与部分应用
2014-04-03 15:01
197 查看
函数式设计的核心与函数的应用以及函数如何作为算法的基本模块有关。利用局部套用技术可以把所有函数看成是函数类的成员,这些函数只有一个形参,有了局部套用,才有部分应用。部分应用是使函数模块化成为可能的两个技术之一,另一个是组合。
C#函数式程序设计之参数的解耦
局部套用是一种转换技术,它把一个需要接收多个参数的函数转换为一系列函数,后者每次只接受一个参数并返回序列中的下一个函数。在这个函数链的末尾,所有的参数都可以使用,并允许原算法执行自己的操作。
考虑下面这个简单的函数,它使用了与C#2.0兼容的匿名方法定义语法:
这个加法函数接受两个参数后返回两个数的相加结果,调用这个函数时,调用程序必须同时提供两个参数,C#语法约束不允许任何其他方法。
要把局部套用技术应用于这个函数,意味着要创建一个一次只能接受一个参数且返回下一个函数的函数,即如下:
局部套用的基本原理也可以应用于用Lambda语法定义的函数:
使用局部套用后的函数如下:
现在把局部套用技术应用于任意个参数上,假设有一个函数有以下的参数列表:
局部套用后的函数签名格式如下:
Lambda表达式主体部分代码,即最后一个=> 运算符的右侧部分,在转换过程中保持不变。
类型排列形式的变化遵从同样的规则,考虑如下的泛型委托类型:
应用局部套用后得到如下的类型排列形式:
有趣的是,如果显式提供Lambda表达式的类型或者C#2.0匿名方法的类型,则采用类型推断也可以推断出泛型参数,这令人感到奇怪,因为在同样的情形下,无法用var关键字把函数保存到一个变量中:
对于内联的Lambda表达式无法调用扩展方法。
局部套用技术也可以应用于C#类声明的比较常规的方法。静态方法和实例方法都可以应用局部套用技术。此外,类使得局部套用函数的外部调用成为可能。
C#函数式程序设计之调用函数的各部分
使用局部套用格式函数的最主要理由是只需要部分计算参数而不是全部参数就可以调用这个函数。这个过程就是所谓的部分应用,部分应用是一种函数构建技术。
考虑下面这段代码,它使用一个从零开始采用局部套用格式的函数:
这里调用了局部套用函数add,但是只给它传递一个参数,显然, 在这种情况下无法进行加法计算,因为它需要两个参数,用一个参数调用将返回一个新函数。我们不是立即调用这个新函数,而是把它保存在变量中供以后使用。
调用这个新创建的函数可以像调用其他函数那样:
通常,部分应用接受一个本质属于泛型的函数,创建一个毕竟专用的新函数。
C#函数式程序设计之参数顺序的重要性
当应用局部套用技术和部分应用技术时,说明参数顺序的重要性有一个简单的理由:函数的部分应用只能从参数列表的起始位置开始。在决定参数的顺序时,最重要的是考虑函数中哪个参数最有可能使用部分应用。
C#函数式程序设计之参数的解耦
局部套用是一种转换技术,它把一个需要接收多个参数的函数转换为一系列函数,后者每次只接受一个参数并返回序列中的下一个函数。在这个函数链的末尾,所有的参数都可以使用,并允许原算法执行自己的操作。
考虑下面这个简单的函数,它使用了与C#2.0兼容的匿名方法定义语法:
Func<int, int, int> add = delegate(int x, int y) { return x + y; };
这个加法函数接受两个参数后返回两个数的相加结果,调用这个函数时,调用程序必须同时提供两个参数,C#语法约束不允许任何其他方法。
要把局部套用技术应用于这个函数,意味着要创建一个一次只能接受一个参数且返回下一个函数的函数,即如下:
Func<int, Func<int, int>> add = delegate(int x) { return delegate(int y) { return x + y; }; };
局部套用的基本原理也可以应用于用Lambda语法定义的函数:
Func<int, int, int> addTest = (x, y) => x + y;
使用局部套用后的函数如下:
Func<int, Func<int, int>> addTest = x => (y => x + y);
现在把局部套用技术应用于任意个参数上,假设有一个函数有以下的参数列表:
Func<...> f = (part1, part2, part3, ..., partX) => ...;
局部套用后的函数签名格式如下:
Func<...> cf = part1 => part2 => part3 => ... => partX => ...;
Lambda表达式主体部分代码,即最后一个=> 运算符的右侧部分,在转换过程中保持不变。
类型排列形式的变化遵从同样的规则,考虑如下的泛型委托类型:
Func<int, bool, string, decimal, double>
应用局部套用后得到如下的类型排列形式:
Func<int, Func<bool, Func<string, Func<decimal, double>>>>
有趣的是,如果显式提供Lambda表达式的类型或者C#2.0匿名方法的类型,则采用类型推断也可以推断出泛型参数,这令人感到奇怪,因为在同样的情形下,无法用var关键字把函数保存到一个变量中:
// this is invalid var mult = (int x, int y) => x * y;
对于内联的Lambda表达式无法调用扩展方法。
局部套用技术也可以应用于C#类声明的比较常规的方法。静态方法和实例方法都可以应用局部套用技术。此外,类使得局部套用函数的外部调用成为可能。
C#函数式程序设计之调用函数的各部分
使用局部套用格式函数的最主要理由是只需要部分计算参数而不是全部参数就可以调用这个函数。这个过程就是所谓的部分应用,部分应用是一种函数构建技术。
考虑下面这段代码,它使用一个从零开始采用局部套用格式的函数:
Func<int, Func<int, int>> add = x => y => x + y; var add5 = add(5);
这里调用了局部套用函数add,但是只给它传递一个参数,显然, 在这种情况下无法进行加法计算,因为它需要两个参数,用一个参数调用将返回一个新函数。我们不是立即调用这个新函数,而是把它保存在变量中供以后使用。
调用这个新创建的函数可以像调用其他函数那样:
int result = add5(37);
通常,部分应用接受一个本质属于泛型的函数,创建一个毕竟专用的新函数。
C#函数式程序设计之参数顺序的重要性
当应用局部套用技术和部分应用技术时,说明参数顺序的重要性有一个简单的理由:函数的部分应用只能从参数列表的起始位置开始。在决定参数的顺序时,最重要的是考虑函数中哪个参数最有可能使用部分应用。
相关文章推荐
- Spark(七):局部套用和部分应用。
- 函数式编程中局部应用(Partial Application)和局部套用(Currying)的区别
- Reductionism and Holism in Programming 归约与整体哲学方法在程序设计中的应用
- Day11多态部分-6 【1.4 多态的应用以及注意事项】
- Microsoft Azure IoT Hub应用 – 第二部分:连接传感器以及 IoT 车辆
- 应用MaxCompute实现变压器局部放电相位分析
- 解析C++普通局部变量与指针类型的对象变量的应用区别
- 第10周 C语言及程序设计提高例程-40 小小型应用系统开发指导(四)
- linux应用编程笔记(8)多进程程序设计
- Spring 事务管理高级应用难点剖析: 第 3 部分
- 声波通信(声波传输)在iOS、Android中的应用场景深入分析(含部分声波通信源代码)
- Spring 事务管理高级应用难点剖析: 第 2 部分
- [全程建模]UML应用与实践的对话——某国外大型业务系统对话的第二部分
- 使用 Spring Batch 构建企业级批处理应用: 第 2 部分
- JSqlParser基本应用文档-select部分
- 嵌入式linux面试题解析(三)——Linux应用编程部分一
- 部分网络应用的要求
- 使用 Apache OpenJPA 开发 EJB 3.0 应用,第 1 部分: OpenJPA 与 EJB 3.0
- C程序设计语言--全局/局部变量、头文件、堆栈空间、静态变量
- 数据结构、算法与应用C++语言描述(第二版) 第一章部分练习参考答案