函數語言程式設計(2) 高階函式

周見智發表於2014-09-02

  上一篇部落格介紹了函數語言程式設計中的基礎知識:

1)什麼是程式設計正規化;

2)程式設計函式與數學函式的關係。

  上篇文章介紹了函數語言程式設計屬於宣告式程式設計正規化中的一種,它仿照數學概念中的公式演算去解決問題,是一種更接近數學語言的程式設計方式。並且我們知道函數語言程式設計中所有的函式都是“純函式(Pure Function)”,因為只有純函式才符合數學中對函式的定義,即:

1)函式均有輸入(均帶有引數)、均有輸出(函式有返回值);

2)使用相同引數呼叫函式,得到的返回值無論何時均相等(不受其他因素影響)。

  數學函式中包含一類函式叫“高階函式”,它指“接收一個(多個)函式作為輸入,或者返回一個函式”的函式。在函數語言程式設計中,同樣存在這樣的高階函式。只要一個函式包含有一個(多個)函式作為引數,或者返回另外一個函式,那麼這個函式就稱為“高階函式”。在.NET中我們使用委託來封裝方法,這樣方法就可以像普通型別一樣作為程式之間傳遞的引數、返回值。在.NET中已經有很多場合使用委託作為函式的引數,比如在非同步程式設計時呼叫的一些方法均帶有AsyncCallback委託型別的引數(BeginInvoke等),尤其是C#3.0出現之後,我們在使用一些類似Select()、Where()等擴充套件方法時,這些方法均會包含一個委託型別的引數:

1 string[] names = { "abc", "def", "ghi", "jkl", "mno" };
2 IEnumerable<string> query = names
3     .Where(n => n.Contains("a"))
4     .OrderBy(n => n.Length)
5     .Select(n => n.ToUpper());
6 foreach (string name in query) Console.WriteLine(name);

注意上面程式碼中使用Lambda表示式就是快速建立委託的一種方式。並且每個委託的簽名幾乎都一致:包含輸入引數,有返回值

  到現在為止,我們很少碰到返回值是委託型別的函式。並不是沒有這樣的函式,只能說C#在容納“函數語言程式設計”的程度還不是很夠。我們完全可以自己編寫一個返回委託型別的“高階函式”,比如數學中為一個函式求導函式的過程:

1 public delegate double Function1X(double x);   //一元函式
2 public Function1X GetDerivative(Function1X func)  //高階函式,函式作為輸入、返回值
3 {
4      double deltaX = 0.00000001;
5      return x => (func(x+deltaX)-func(x))/deltaX;  //導數定義(近似)
6 }

如上程式碼所示,GetDerivative()方法包含一個委託型別引數,代表需要求導函式的函式;並且返回一個委託型別,代表求得的導函式。GetDerivative()方法既包含函式作為引數,又能返回一個函式,因此它屬於“高階函式”。

總結:

1)在程式設計中,我們可以使用“純函式”來代表一個數學函式。“純函式”無副作用(Side-Effect),並且符合數學中對函式的定義。可以這麼說,程式設計函式涵蓋的範圍包含數學函式;

2)如果一個純函式的引數又是一個函式,或者該純函式能夠返回另一個函式,那麼這個純函式就稱為“高階函式”,它與數學中的高階函式對應。

到目前為止,我所講到的所有內容都是為了讓你在“程式”和“數學”之間找到一個共同點,能夠一一類比。而這個過程中,“純函式”無疑是重點。

  下面分享一個demo,能夠繪製任意給定函式的曲線圖,並能夠繪製指定點(X)處的切線。demo中主要演示一個求導函式的高階函式和一個求切線函式的高階函式

 1   /// <summary>
 2         /// 求導函式 近似
 3         /// </summary>
 4         /// <param name="func"></param>
 5         /// <returns></returns>
 6         private Function1X Get(Function1X func)
 7         {
 8             double delatX = 0.00000000001;
 9             return x => (func(x + delatX) - func(x)) / delatX;
10         }
11 
12         /// <summary>
13         /// 根據斜率和(x,y)得到切線方程
14         /// </summary>
15         /// <param name="k"></param>
16         /// <param name="x"></param>
17         /// <param name="y"></param>
18         /// <returns></returns>
19         private Function1X Get2(double k, double x, double y)
20         {
21             // y = kx + b
22             // b = y - kx
23             double b = y - k * x;
24             return a => k * a + b;
25         }
View Code

(demo中解析函式表示式的過程使用到了老外的方法,站在巨人肩膀上:))下面是效果圖:

原始碼下載地址:http://files.cnblogs.com/xiaozhi_5638/Functional_Program.rar

 

函數語言程式設計(1)

相關文章