拿 C# 搞函数式编程
最近闲下来了,准备出一个 C# 搞 FP 的合集。本合集所有代码均以 C# 8 为示例。
可能你说,为什么要这么做呢?回答:为了好玩。另外,意义党们请 gun cu ke!
C# 有委托,而且有 Func<> 和 Action<>,可以说函数被视为一等公民,跟 int、bool 等类型并没有什么区别。那么很多事情就简单了。
纯函数
什么是纯函数呢?纯函数就是 f(x),它们接收参数,得到结果,并且相同的参数得到的结果一定是相同的,用映射来说,它是满射的。另外这个函数不会改变任何的状态值,它是无副作用的。
柯里化
首先,有一个东西让我觉得不爽,那就是一般来说 C# 里的函数调用不是柯里化的,这也就意味着我没法一个一个传参数进去,也没法把传了一部分参数的调用作为一个新函数拿去给别的地方用,那要怎么办呢?
自己动手,丰衣足食!
一个标准的加法函数可以这么写:
var function = new Func<int, int, int> ((x, y) => x + y);function(1, 2); // returns 3
如果我们想以柯里化形式调用的话,理想状态是这么个样子的:
function 1 2
但是这个括号我们是省不了的,所以这样也是可以接受的:
function(1)(2);
我们看一下这个调用形式,不就是 Func<int, Func<int, int>> 嘛!so easy~
我们只需要把 Func<int, int, int> 转化为 Func<int, Func<int, int>>:
Func<int, Func<int, int>> Currying(Func<int, int, int> f)=> x => y => f(x, y);
这样写就 ok 啦。进一步改造成扩展方法:
public static class CurryingExtensions{public static Func<int, Func<int, int>> Currying(this Func<int, int, int> f)=> x => y => f(x, y);}
于是我们只需要:
var function = new Func<int, int, int> ((x, y) => x + y) .Currying();function(1)(2); // returns 3
就可以采用柯里化形式调用该函数啦。
进一步我们用泛型改造,让柯里化适用于任何类型:
public static class CurryingExtensions{public static Func<T1, Func<T2, TOutput>> Currying<T1, T2, TOutput>(this Func<T1, T2, TOuput> f)=> x => y => f(x, y);}
如果遇到更多参数,我们只需要给这个静态类里面再加一个扩展方法即可。
那 Action<> 呢?这个东西在我看来完全就是副作用,具体下方有讲,我们不用他(逃
Unit
什么是 Unit 呢?Unit 就是任何函数调用后如果没有结果,就会返回的一个东西。
可能你说,void 不就可以了?
但是如果一个纯函数,它没有返回值(即 Action<>),意味着这个函数它有输入没输出,那这个函数除了能用来产生副作用之外,就什么都干不了了。这不清真!
因此我们需要一个 Unit 来代替 void,偷个懒,这个 Unit 就用 ulong 来代替吧。
高阶函数
什么叫做高阶函数,把函数当作参数传给另一个函数,接收这个函数参数的函数就叫做高阶函数。
举个例子:f(g(x)),f 即高阶函数。
假设我们现在要开一个超市,超市有很多的产品,每种产品价格不同,不同产品可能还有各自的折扣。我们有很多种快乐水,每种快乐水价格不一样,可口快乐水 3.5 块,百事快乐水 3 块,麦当劳快乐水 9 块,快乐水价格计算函数:
var happyWater = new Func<float, int, float>
((float price, int number) => number * price)
.Currying();
// 调用:happyWater(快乐水单价)(快乐水件数);
var cocaHappyWater = happyWater(3.5f);
var pepsiHappyWater = happyWater(3);
var mcdHappyWater = happyWater(9);
超市可能有折扣,A 超市不打折,B 超市打八折,计算价格函数:
var calcPrice = new Func<Func<int, float>, float, int, float> ((calc, discount, number) => discount * calc(number)) .Currying();// 调用:calcPrice(快乐水价格计算函数)(超市折扣)(快乐水件数);
现在我们分别在 A 超市买百事快乐水、B 超市买可口快乐水,麦当劳的太贵了我们不买,价格计算函数为:
var pepsiPriceCalc = calcPrice(pepsiHappyWater);var cocaPriceCalc = calcPrice(cocaHappyWater); var priceCalcA = pepsiPriceCalc(1); // A 超市var priceCalcB = cocaPriceCalc(0.8f); // B 超市
最后我们在 A 超市买了 3 瓶百事快乐水,B 超市买了 5 瓶可口快乐水,计算总价:
var priceA = priceCalcA(3);var priceB = priceCalcB(5);var total = priceA + priceB;
最后得到 total = 23 元。
可以看到这些函数都是可拆卸并且可以随意组合的,而且满足 f(g(x)) = g(f(x))。
贴上完整代码示例:
原文链接:https://www.cnblogs.com/hez2010/p/11487006.html
.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com
拿 C# 搞函数式编程相关推荐
- 拿 C# 搞函数式编程 - 2
前一阵子在写 CPU,导致一直没有什么时间去做其他的事情,现在好不容易做完闲下来了,我又可以水文章了哈哈哈哈哈. 有关 FP 的类型部分我打算放到明年再讲,因为现有的 C# 虽然有一个 pattern ...
- 过程或函数的副作用是_Python函数和函数式编程(两万字长文警告!一文彻底搞定函数,建议收藏!)...
Python函数和函数式编程 函数是可重用的程序代码段,在Python中有常用的内置函数,例如len().sum()等. 在Pyhon模块和程序中也可以自定义函数.使用函数可以提高编程效率. 1.函数 ...
- 用通俗易懂的大白话搞明白Java里的函数式编程和Lambda表达式
今天,用通俗易懂的大白话来彻底搞明白Java里的函数式编程和Lambda表达式 为什么引入函数式编程,lambda表达式? 大家都知道,JDK1.8引入了函数式编程,lambda表达式. 那有没有想过 ...
- less 函数_Python中的函数式编程教程,学会用一行代码搞定所有内容
前言 在本文中,您将了解什么是函数范型,以及如何在Python中使用函数式编程.在Python中,函数式编程中的map和filter可以做与列表相同的事情.这打破了Python的禅宗规则之一,因此函数 ...
- 玩转 JavaScript 面试:何为函数式编程?
函数式编程在 JavaScript 领域着实已经成为一个热门话题.就在几年前,很多 JavaScript 程序员甚至都不知道啥是函数式编程,但是就在近三年里我看到过的每一个大型应用的代码库中都包含了函 ...
- 函数式编程学习之路(三)
入门: 函数式编程之艰难,在于这玩意更接近数学,就是数学之"用",大牛们在云端,玩纯数学去了,弄出一堆公式及概念,码农们爬在地上,辛苦耕耘,要的是看得见摸得着的,函数式编程就是要打 ...
- 测试和恢复性的争论:面向对象vs.函数式编程
Michael Feathers最近的博文在博客社区引发了一场异常激烈的论战.Feathers发表言论说一些面向对象编程语言的内嵌特性有助于测试的进行,并且使用面向对象编程语言编写的代码更容易恢复. ...
- 开发日记-20190517 关键词 函数式编程(一)
前言: 这块其实是我对于<Java函数式编程>的读书笔记,有句话其实说的挺不错,每当你需要二刷一本书的时候,说明这本书你白读了.所以我争取一遍搞定它,不做浪费时间的二刷操作. 第一章< ...
- 函数式编程——做到并发,不可变数据修改就只能复制后修改返回
函数式编程 from:https://coolshell.cn/articles/10822.html 当我们说起函数式编程来说,我们会看到如下函数式编程的长相: 函数式编程的三大特性: immuta ...
最新文章
- C# JSON使用过程中开发的小工具
- 如何打造“智能助理”?阿里对话开发平台这样做
- 每个产品经理都应该知道的机器学习术语
- Pandas-Series知识点总结
- RssTookit使用小结
- 大数据将植物学研究带入新境界
- 数据库中查询的各种连接(左连接,右连接,全连接,内连接,交叉连接,自连接)...
- mysql dbf导入数据库_MySQL数据库如何导入dbf格式数据?
- ubuntu 运行级别initlevel
- MATLAB软件基础
- 《AIX 5L 系统管理技术》学习笔记之第七章设备管理
- 使用C语言编写一个算数的除法运算(保留n位小数)
- ios 后台唤醒应用_iOS 前后台机制以及后台唤醒机制【个人学习】
- 从山寨机看手机的未来
- ET vs Ad hoc
- MIT 18.01 Single Variable Calculus(单变量微积分)课堂笔记【6】——近似和求最值
- 抓取新浪微博好友昵称和性别
- 今日头条还可以引流么?今日头条引流效果怎么样?
- Filecoin矿商史上最全测评,看完这篇谁也坑不了我
- 通过Visual Studio 2019搭建DirectX 12开发环境
热门文章
- 遭遇“烧钱瓶颈” 优酷成本结构堪忧
- 合肥工业大学计算机学院王院长,王青山(合肥工业大学教授)_百度百科
- alexa语音实现_如何通过语音删除Alexa录音
- 10以内数的组成分解图_大班数学教案《10以内数的组成》
- vcenter 6.7 (vcsa)部署指南
- 狐狸文│区块链发展的正路
- 《微软云计算Microsoft Azure部署与管理指南》即将上市!!!
- exec和sp_executesql
- 本地环境和测试环境搭建
- 5.[BX]和Loop指令