
Java 開發者的函數式程式設計(3)List 處理模式
Java 開發者的函數式程式設計(2)代數資料型態 << 前情 在使用代數資料型態定義(或說是模擬)了清單類型之後,我們回到 Java 開發者的函數式程式設計(2) 中留下的最後一個問題。現在我們寫的是 Java,該怎麼將以下的程式碼改寫為 Java? sum [] = 0 sum (x:xs) = x + sum xs Java 不支援模式匹配(Pattern match),我們可以使用 public static Integer sum(List<Integer> lt) { if(lt == Nil) return 0; else return lt.head() + sum(lt.tail()); } 在定義了 public static List<Integer> addOne(List<Integer> lt) { if(lt == Nil) return nil(); else return cons(lt.head() + 1, addOne(lt.tail())); } 類似地,如果想定義一個方法,將清單中每個元素減 2 後傳回新清單,那麼就只要將程式碼中 public interface F1<P, R> { R apply(P p); } 在處理清單時,將清單映射為另一個新清單是常見的處理模式,可以定義一個 public class AlgebraicType { ... public static <T, R> List<R> map(List<T> lt, F1<T, R> f) { if(lt == Nil) return nil(); return cons(f.apply(lt.head()), map(lt.tail(), f)); } } 那麼,要對清單中每個元素加一的話,就可以這麼做: map(list(1, 2, 3, 4, 5), x -> x + 1); 要對清單中每個元素減二的話,就可以這麼做: map(list(1, 2, 3, 4, 5), x -> x - 2); 要對清單中每個元素乘三的話,就可以這麼做: map(list(1, 2, 3, 4, 5), x -> x * 3); 這種 public static List<Integer> greaterThanThree(List<Integer> lt) { if(lt == Nil) return nil(); else { if(lt.head() > 3) { return cons(lt.head(), greaterThanThree(lt.tail())); } else { return greaterThanThree(lt.tail()); } } } 如果想將清單中小於 10 的元素過濾出來成為新清單呢? public static List<Integer> smallerThanTen(List<Integer> lt) { if(lt == Nil) return nil(); else { if(lt.head() < 10) { return cons(lt.head(), smallerThanTen(lt.tail())); } else { return smallerThanTen(lt.tail()); } } } 在處理清單時,對元素進行過濾以得到新清單,這是個常見處理模式,我們可以定義一個 public class AlgebraicType { ... public static <T> List<T> filter(List<T> lt, F1<T, Boolean> f) { if(lt == Nil) return nil(); else { if(f.apply(lt.head())) { return cons(lt.head(), filter(lt.tail(), f)); } else { return filter(lt.tail(), f); } } } } 接著,要過濾出清單中大於 3 的元素就可以這麼做: filter(list(1, 2, 3, 4, 5), x -> x > 3); 要過濾出清單中小於 10 的元素就可以這麼做: filter(list(10, 19, 3, 4, 5), x -> x < 10); 這個 public interface F2 { R apply(R r, P p); } 接著,就可以如下定義一個 public class AlgebraicType { ... public static <T, R> R reduce(List<T> lt, F2<T, R> f, R r) { if(lt == Nil) return r; else { return reduce(lt.tail(), f, f.apply(r, lt.head())); } } } 那麼,對清單元素進行加總,就可以這麼做: reduce(list(1, 2, 3, 4, 5), (sum, x) -> sum + x, 0); 對於函數式程式設計的初學者來說,想瞭解 這個 然而,這邊的重點在於,如果以函數式風格來編寫程式,你會很容易發覺函式間具有相近結構,因而能輕易地提煉為更高階的抽象以進行重用,這邊提到的 |