函數式編程中的基本概念

函數簽名

假設有一個函數 f,輸入一個 int 值,返回一個 string 值,在 C# 中,該函數可以表示爲:

Func<int, string>

我們可以使用箭頭(→)符號來表示:

f : int → string

箭頭符號是函數式編程社區的標準函數符號,與語言無關。

當沒有輸入或沒有輸出(void)時,用 () 表示。如果有多個輸入或輸出,則用元組表示。

例如:

Func<string>
Func<int, int, int>

分別表示爲:

() → string
(int, int) → int

對於高階函數,可以嵌套表示。

例如 IEnumerable.Where 的簽名:

Func<IEnumerable<T>, Func<T, bool>, IEnumerable<T>>

// IEnumerable<T> Where<T>(this IEnumerable<T> source, Func<T, bool> predicate);

可以表示爲:

(IEnumerable<T>, (T → bool)) → IEnumerable<T>

函數的純潔性

純函數 是指沒有任何副作用的函數,除了根據輸入值計算輸出值之外,什麼也不做。而不純函數則可能導致副作用。

副作用包括:

  • 使全局狀態改變:這裏的“全局”是指函數作用域之外。
  • 改變其輸入參數
  • 拋出異常
  • 執行任何 I/O 操作

純函數擁有許多的好處:

  • 並行化:由於輸出值僅依賴於輸入值,所以可以並行執行任務。
  • 惰性求值
  • 記憶化:緩存函數結果,以便只計算一次。

誠實的函數

誠實的函數始終履行自己的簽名。

例如如下函數,就是一個誠實的函數:

public int Square(int n) => n * n;

而如下函數則是不誠實的:

public int Square(int n)
{
    if (n < 0) throw new ArgumentException();

    return n * n;
}

因爲它可能返回一個 int 值,還可能拋出異常。


參考:《C# 函數式編程》 Enrico Buonanno 著

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章