日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

拿 C# 搞函数式编程

發布時間:2023/12/4 C# 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 拿 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# 搞函数式编程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。