從 Java 版的 Higher-Order Functions for Parser 來看

再自我推廣一次:我用 Java 寫 Higher-Order Functions for Parser ,是長得這樣: http://github.com/YauHsien/ParsecJ

物件導向程式語言與函數式程式語言的對應,是這樣的:

設想以下連續加法函數:

sum :: Num a => [a] -> a

sum [] = 0

sum (x:xs) = x + sum xs

用 Java 寫起來應該是:

import util.Function;

public class Sum<T> extends Function<LinkedList<T>, T> {

@Override

protected T apply1(LinkedList<T> inp) {

if (inp.size() == 0)

return 0;

T head = inp.pollFirst(); // Side Effect: inp 的第一個元素被抽掉

return head + this.apply(inp);

// 問題來了:表面上是 T ,但用了 + 則隱含 T 可能是數字或 class String

}

}

要將函數式程式對應為物件導向思考,我所抓到的概念有這些:

  1. 函數式程式 sum 由函數型態 (Num a => [a] -> a) 與實作 (sum [] = 0; sum (x:xs) = x + sum xs) 構成,前者是介面,後者是實作。
  2. 介面與實作的關係很多:可以是 class method 做為介面,而實作做為實作,或者可以是 interface 讓實作 realize ,或者可以是根據 class 製造出 instance ,或者可以是從工廠產生物品。當然,也可以像我,用 Generics 明確說明函數型態。
  3. 介面與實作的關係,可以只有 1 對 1 ,或者可以 1 對多。
  4. 函數寫成物件導向的 class ,可以寫成如同 Fuction f = new Function(); Function g = f.apply(x); g.apply(y) 之類的樣子,而且這樣寫,可以做出 curry 與 lazy evaluation 。
  5. 多型很麻煩:例如做加減乘除,同樣是整數,經過加、減、乘都還保持為整數,但是,一經過除法,就擴充為分數或浮點數了,而且也可以再套用加、減、乘、除在分數或浮點數。
  6. 如果用 Java Generics 製作多型,對於型態的特殊性的陳述,如 Num a ,也值得設想。
  7. 值的 clone 或 deep copy 是重要的基礎。當然,實作一定也可以在某些地方巧用不 clone 而做原值更新的撇步。

 

廣告

About 黃耀賢 (Yau-Hsien Huang)

熱愛 Erlang ,並且有相關工作經驗。喜歡程式語言。喜歡邏輯。目前用 Python 工作。
本篇發表於 Problem, Uncategorized。將永久鏈結加入書籤。