深入探討 FP 之 Pure Function 與 Side Effect

栏目: 后端 · 前端 · 发布时间: 6年前

内容简介:Functional Programming 要求 Data 與 Function 分離,其中 Data 要求的是 Immutability,而 Function 要求的就是 Pure Function。這是 FP 的兩大基石,所有其他的特性都是由這兩個基本原則展開。Pure Function 最簡單的定義就是C# 7.2

Functional Programming 要求 Data 與 Function 分離,其中 Data 要求的是 Immutability,而 Function 要求的就是 Pure Function。這是 FP 的兩大基石,所有其他的特性都是由這兩個基本原則展開。

Pure Function 最簡單的定義就是 不能產生 Side Effect ,但究竟什麼是 Side Effect 呢 ?

Version

C# 7.2

本文為 Funtional Programming in C# 一書第二章的讀後心得

Definition

Pure Function

  • 與 Mathematical Function 一致
  • Ouput 僅與 Input Argument 相關
  • 不會產生 Side Effect

與 Pure Function 相對的,就是 Impure Function:

Impure Function

  • 大部分 Programming Function
  • 除了 Input Argument 外,尚有其他因素影響 Output (Field、Exception、I/O)
  • 會產生 Side Effect

我們可發現 Pure Function 與 Impure Function 是相對的,其他定義都很容易理解,唯獨 Side Effect 需要另外解釋。

Side Effect

  • Mutate Global State
  • Mutate Input Argument
  • Throw Exception
  • Perform I/O Operation

Mutate Global State

凡在 function 以外的 scope,就算是 Global State,如 OOP 的 field,也被視為 Global State。

修改 Global State 被視為有 Side Effect。

Program.cs

class Program
{
    static void Main(string[] args)
    {
        var counter = new Counter(0);
        var count = counter.AddOne()
                           .AddOne()
                           .Count;

        Console.WriteLine(count);
    }
}
// 2

counter 增加 2 次,結果為 2

Counter.cs

public class Counter
{
    public int Count { get; private set; }

    public Counter(int count)
    {
        Count = count;
    }

    public Counter AddOne()
    {
        Count++;
        return this;
    }
}

OOP 強調 Data 與 Function 合一,所以會將 Count 視為 field,封裝在 Counter class 內。

AddOne() 被視為有 Side Effect,因為其修改了 function 外部的 Count field,屬於 Global State。

為了做 Fluent Interface,OOP 會以 return this 方式。

Counter.cs

public class Counter
{
    public int Count { get; }

    public Counter(int count)
    {
        Count = count;
    }
}
    
public static class CounterExt
{
    public static Counter AddOne(this Counter counter)
    {
        return new Counter(counter.Count + 1); 
    }
}

FP 強調 Data 與 Function 分家,因此 Data 屬於 Counter class,而 Function 屬於 CounterExt class。

AddOne() 沒有 Side Effect,因為根據 argument 得到目前的 count,計算後回傳新的 Counter object,完全與 function 外部無關。

FP 藉由 Extension Method 達成 Fluent Interface。

儘管由 OOP 改用 FP,但 client 的寫法完全沒有改變

Mutate Input Argument

修改 function 的 argument,而造成 function 外界的 data 被修改,也視為 Side Effect。

decimal RecomputeTotal(Order order, List<OrderLine> linesToDelete)
{
    var result = 0m;
    
    foreach(var line in order.OrderLines)
    {
        if (line.Quantity == 0)
        {
            linesToDelete.Add(line);
        }
        else
        {
            result += line.Product.Price * line.Quantity;
        }
    }
    
    return result;
}

RecomputeTotal 被視為有 Side Effect,因為新增了 linesToDelete List,造成對 RecomputeTotal() function 外部的 data 有影響。

(decimal, IEnumerable<OrderLine>) RecomputeTotal(Order)
    => (order.OrderLines.Sum(x => x.Product.Price * x.Quantity)),
        order.OrderLines.Where(x => x.Quantity == 0));

使用回傳 order.OrderLines.Where(x => x.Quantity == 0) 取代新增 linesToDelete List,如此不會影響 function 外部 data,因此沒有 Side Effect。

Throw Exception

因為以下兩個原因,Throw Exception 也被視為 Side Effect:

try catch

FP 也有自己的 Exception 處理機制,如 F# 的 Result 、Haskell 的 Either

Perform I/O Operation

在現實世界中,不可能所有 function 都在計算或者 mapping,如

  • 呼叫 API
  • 寫入資料庫、寫到 console
  • 讀出系統時間

深入探討 FP 之 Pure Function 與 Side Effect

這些都屬於無法避免的 Side Effect,但我們可將 Side Effect 集中在 Pure Function 前後,而不是在 function 內隨意的 Side Effect。

Conclusion

  • Pure Function 與 Side Effect 為 FP 的入門磚,看似基本,但實務上並不容易實現,常常一不小心就寫出 Impure Function
  • I/O 是無法避免的 Side Effect,但 FP 能將 Side Effect 降到最低

Sample Code

完整的範例可以在我的 GitHub 上找到

Reference

Enrico Buonanno, Functional Programming in C#


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

自品牌

自品牌

陈为、孙郁婷 / 机械工业出版社 / 2015-9-7 / 39

移动互联网来势汹涌,让品牌重新回到人的时代。微信旗帜鲜明地宣示,“再小的个体也有自己的品牌”。《自品牌:个人如何玩转移动互联网时代》作者历经一年,深度访谈10位嘉宾,挖掘其品牌与商业成功密码。吴晓波、雕爷、罗永浩、鬼脚七、马佳佳……这些商业新浪潮中的探路者与领军者,要么是传统领域的老将,要么是新领域里的先锋,但都能以新媒体为载体,构建个人品牌,打造商业生态,抓住互联网的时代红利,顺风而起,顺势而为......一起来看看 《自品牌》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码