8. 一級函式
• 有些語言中函式是一等公民(First-class citizen)
– 高階函式(High order function)
function doSome(param) {
// 作些事
}
var doSome = function(param) {
// 作些事
};
function doAction(opt) {
return function(param) {
// 作些事 作些事
//
}; };
};
9. What is
http://en.wikipedia.org/wiki/Lambda
In programming languages such as
Lisp and Python, lambda is an
operator used to denote
anonymous functions or closures
/lambda/
10. λ 演算(Lambda calculus)
• 每個表達式(Expression)代表具單一參數函數
• 參數本身亦可接受具有單一參數的函式
• f(x) = x * 2 可匿名地表示為 …
λ x. x * 2
x -> x * 2
11. λ 演算(Lambda calculus)
• 如果要套用 x 為 2
(x -> x * 2)(2)
= 2 * 2
= 4
• g(y) = y -1 代入 f(x) 匿名地表達為…
(y -> y - 1)(x -> x * 2)
= x -> x * 2 - 1
12. λ 演算(Lambda calculus)
• 多參數的函數可使用單參數函數套用而成
(x, y) -> x * x + y * y
= x -> (y -> x * x + y * y)
•若x為2而y為3
(x -> (y -> x * x + y * y))(2)(3)
= (y -> 2 * 2 + y * y)(3)
= 4 + 3 * 3
= 4 + 9
= 13
13. λ 演算(Lambda calculus)
• 可用來表現任何可計算函數
• 可使用函數實現控制結構(如 if、forEach等)
• 一個小型通用語言
butThat = cond->fv->tv->
(cond or fv) and (cond and tv)
butThat(true)(10)(20)
= (true or 10) and (true and 20)
= true and 20
= 20
14. 一級函式與 λ 演算
• 不同語言提供不同程度的 Lambda 表達式支援
(x -> x * 2)(2)
function(x) {
return x * 2;
}(2);
24. 不只是語法蜜糖
• 語彙範圍(Lexical scoping)
– Lambda 語法本體中的名稱與包裹環境相同
public class Hello {
Runnable r1 = () -> { out.println(this); }
Runnable r2 = () -> { out.println(toString()); }
public String toString() { return "Hello, world!"; }
public static void main(String... args) {
new Hello().r1.run();
new Hello().r2.run();
}
}
25. 不只是語法蜜糖
• 變數捕捉(Variable capture)
– 與 final 等效的區域變數不需要 final
Callable<String> helloCallable(String name) {
String hello = "Hello";
return () -> (hello + ", " + name);
}
• 編譯錯誤...
int sum = 0;
list.forEach(e -> { sum += e.size(); });
• 建議...
int sum = list.map(e -> e.size())
.reduce(0, (a, b) -> a + b);
26. 方法參考(Method reference)
• 類別靜態方法
public class Person {
...
public static int compareByAge(Person a, Person b) { ... }
public static int compareByName(Person a, Person b) { ... }
}
Person[] people = ...
// Arrays.sort(people, (a, b) -> a.getAge() – b.getAge());
Arrays.sort(people, Person::compareByAge);
interface Block<T> { void run(T arg); }
Block<Integer> b1 = System::exit; // void exit(int status)
Block<String[]> b2 = Arrays::sort; // void sort(Object[] a)
Block<String> b3 = MyProgram::main; // void main(String... args)
Runnable r = MyProgram::main; // void main(String... args)
27. 方法參考(Method reference)
• 特定物件實例方法
public class ComparisonProvider {
public int compareByName(Person p1, Person p2) { ... }
public int compareByAge(Person p1, Person p2) { ... }
}
...
ComparisonProvider comparisonProvider = ...;
Arrays.sort(people, comparisonProvider::compareByName);
• 實例方法中可帶物件狀態
– 相當於讓 Lambda 語法帶有狀態(Closure 的替代?)
46. 全部放在一起
List<Album> favs = new ArrayList<>();
for (Album a : albums) {
boolean hasFavorite = false;
for (Track t : a.tracks) {
if (t.rating >= 4) {
hasFavorite = true;
break;
}
}
if (hasFavorite)
favs.add(a);
}
Collections.sort(favs, new Comparator<Album>() {
public int compare(Album a1, Album a2) {
return a1.name.compareTo(a2.name);
}});
50. 函數式風格的可能性
• 費式數的定義
{ F0 = 0, F1 = 1, Fn = Fn-1 + Fn-2 }
• 指令式程式設計(Imperative programming)?
int fib(int n) {
int a = 1; int b = 1;
for(int i = 2; i < n; i++) {
int tmp = b; b = a + b; a = tmp;
}
return b;
}
52. 函數式風格的可能性
• 函數式語言的特徵 fib 0 = 0
fib 1 = 1
– 一級函式 fib n = fib (n-1) + fib (n-2)
– Immutable sum [] = 0
– Lazy evaluation sum (x:xs) = x + sum xs
– Pattern match
{2 * x | x ∈ {1, 2..100}}
– List comprehension
[2 * x | x <- [1, 2..100]]
– Curried function
f x y = x + y
g y = f 1 y
53. 函數式風格的可能性
• JDK8 有多少函數式風格的特性?
– 直接支援 Lambda 語法
– 使用 final 變數強制 Immutable
– 以 API 封裝複雜細節達到…
– 延遲求值
– 模式匹配
– List comprehension
– Partially applied 與 Curried function
54. 函數式風格的可能性
• 以 API 封裝複雜細節,留下函數式外觀給使用者
– Functional Java(functionaljava.org)
– 目的就是為了讓 Java 實現函數式風格
– 主要針對 JDK5 以上
– 使用匿名內部類別繼承抽象類別
final Array<String> a = array("Hello", "There", "what");
final boolean b = a.exists(new F<String, Boolean>() {
public Boolean f(final String s) {
return fromString(s).forall(isLowerCase);
}
});
boolean b = a.exists(s -> fromString(s).forall(isLowerCase));