iT邦幫忙

2022 iThome 鐵人賽

DAY 13
0

在前幾天的內容中常常提到純函數、副作用,但究竟是什麼意思呢?我覺得並不好解釋,但是我們可以觀察:

  1. 給定相同的輸入,就會得到相同的輸出

    在Day2與Day3,我們講到了函數的對應關係,而我們對希望純函數不會因為外界的狀態改變而改變他的對應關係,舉例來說:

    • Math.Round()是純函數,給定Round(5.1,0)就會得到5,不會因為轉生到異世界就變成6(不過異世界通常好像都沒有電腦)。
    • string.ToUpper()是純函數,輸出的文字不會有小寫英文字母。
    • HttpClinetGetAsync 不是純函數,回傳值會取決於當下的網路環境,有可能是200也有可能是404。
    • DateTime.Now()不是純函數,因為得到的值總是不一樣
  2. 純函數不會改變狀態

    不改變狀態這一點,其實就是所謂的副作用,也是不變性在FP為什麼重要:

    • List<T>.Sort 不是純函數,因為他直接改變了原來的集合
    • Enumerable.OrderBy 是純函數,他不改變原來的集合而是返回新的值
    • Console.WriteLine 不是純函數,他改變了螢幕的狀態

純函數的優點

純函數的優點來自於限制,因為我們限制了輸入與輸出以及不能有副作用,所以在設計階段就獲得了

  1. 純函數容易理解

    函數只關注輸入與輸出,我們不需要理會函數裡面的行為

    var number = "一";
    // 對於能不能轉換成功沒有定義
    var n1 = int.Parse(number);
    
    // 可以進一步包裝成Option,因為結果能夠預期,更容易處理
    var isInt = int.TryParse(out var n2);
    
  2. 純函數容易測試

    舉例來說,當程式碼裡面用到了DateTime.Now()就會不容易測試,因為當下的時間會不斷的改變。

    public bool CheckIfExpired(Datetime datetime) => datetime > Datetime.Now();
    

    在OOP的做法中,我們可能會用一個物件去包裝Datetime.Now(),並且在撰寫測試時Mock這個物件,使取得當下時間是固定的。

    但是在FP中,我們希望寫純函數,所以設計上會變成

    public bool CheckIfExpired(TimeSpan span) => span > 0
    

小結

今天大概講了一下純函數的概念,主要是為了明天的題目做鋪陳,FP中透過模組包裝函數,實現資料與行為分離,而明天要討論C#中如何實現模組的概念。


上一篇
Day12. Record(2)
下一篇
Day14. Modules
系列文
Functional Programming with C#30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言