lambda/closure – JavaScript、Python、Scala 到 Java SE 7 林信良 http://openhome.cc caterpillar@openhome.cc
以下純屬
Update to date • JDK 7 Features updated ! Plan B has apparently been approved – http://www.baptiste-wicht.com/2010/09/jdk-7- features-updated-plan-b-is-apparently-here/ • 2011 Java SE 7 沒有 Closure … Orz • 2012 Java SE 8 才有 Closure ... XD • 2012 世界末日才有 Closure … 囧rz
議程 • lambda • closure • 動靜之間 • 沒有 lambda/closure 的 Java • Java SE 7 lambda/closure 提案
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/
從 Java…呃!JavaScript 來認識起…
function doSome(param) { // 作些事 } var doSome = function(param) { // 作些事 }; function(param) { * Function literal // 作些事 * Function 實例 }; * new Function('param', '函式本體'); * Anonymous function
既然函式是物件,那麼可以作什麼? • 指定給別的變數 function foo(arg) { document.write(arg , '<br>'); } var zzz = foo; zzz('demo'); • 這跟樓下的是一樣的 … var foo = function(arg) { document.write(arg , '<br>'); }; var zzz = foo; zzz('demo');
既然可以指定給別的變數,就可以… • 作為引數傳入函式中 function show(element) { document.write(element + '<br>'); } [1, 2, 3, 4, 5].forEach(show); • 這跟樓下的是一樣的 … var show = function(element) { document.write(element + '<br>'); }; [1, 2, 3, 4, 5].forEach(show);
文化 與 風格
走訪陣列 var array = [1, 2, 3, 4, 5]; for(var i = 0; i < array.length; i++) { doucment.write(array[i] + '<br>'); } [1, 2, 3, 4, 5].forEach( function(element) { doucment.write(element + '<br>'); } );
可作為引數傳入函式?那就可以設計 callback 函式.. • 實作 forEach Array.prototype.forEach = function(callback) { for(var i = 0; i < this.length; i++) { callback(this[i]); } }; [1, 2, 3, 4, 5].forEach( function(element) { doucment.write(element + '<br>'); } );
當函式是物件時 • 可以根據需要傳遞給另一個名稱參考 • 不再被動呼叫,可主動指導別的函式動作 • 流程中不同演算,設計callback函式代換 簡化的語法 不同的設計
What is closure?
Closure • 文言文…. – 函式物件建立時,自由變數(Free variable )綁定了當時作用範圍中的變數,使被綁定的 變數之作用範圍跟隨著被建立的函式物件 • 白話文 就是….
心愛的跟別人跑了…XD r2
這是一個區域變數 function init() { var local = 10; setInterval( function() { alert(new Date() + ': ' + local); local++; }, 自由變數(Free variable) 3000); } window.onload = init; 網頁資源載入完成後執行一次
• local這樣的變數對函式實字部份的宣告 來說,稱為自由變數(Free variable) • 自由變數真正的意義,必須結合函式實字 以外的環境才可以得知
你說過要跟我海枯石爛啊啊啊啊… init 函式… r2
實際的應用呢?… • 在 JavaScript 中模擬私用性… function Account(money) { var balance = money; this.getBalance = function() { return balance; }; this.deposit = function(money) { if(money > 0) { balance += money; } }; } var account = new Account(1000); account.deposit(500); account.balance = 1000;
var account = new Account(1000); var account = {}; Account.call(account, 1000); function Account(money) { var balance = money; * 函式是物件 this.getBalance = function() { return balance; * 物件可以擁有方法 }; this.deposit = function(money) { if(money > 0) { balance += money; } }; } Closure 綁定的是自由變數本身,而不是其值!
正確的說法叫腳踏兩(多)條船…XD
環環相扣
My name is Python …. def max(m, n): return m if m > n else n print(max(10, 3)) # 顯示 10 maximum = max print(maximum(10, 3)) # 顯示 10 max = lambda m, n: m if m > n else n print(max(10, 3)) # 顯示 10
函式定義 function max(m, n) { def max(m, n): if(m > n) { return m if m > n else n return m; } return n; } 匿名函式 function(m, n) { lambda m, n: m if m > n else n if(m > n) { return m; } return n; };
import math 從函式傳回函式 def prepare_factor(max): # 一些建立質數表的過程,需要一些時間與資源 primes = [i for i in range(2, max) if prime[i] == 1] # 質數表 def factor(num): # 利用質數表進行因式分解的過程 while primes[i] ** 2 <= num: if num % primes[i] == 0: Closure list.append(primes[i]) num //= primes[i] else: i += 1 return factor # 傳回函式 factor = prepare_factor(1000) print(factor(100)) # 顯示 [2, 2, 5, 5]
當函式是物件時 • 可以根據需要傳遞給另一個名稱參考 • 不再被動呼叫,可主動指導別的函式動作 • 流程中不同演算,設計callback函式代換 • 可以形成 Closure 綁定自由變數(資源) • 可以從函式中傳回函式
Python 只作「半套」?。。XD 1 18
• 變數無需宣告就可以直接使用並指定值 • 除非特別使用global或nonlocal指明( Python 3),否則變數範圍(Scope) 總在指定值時建立
def func(): def func(): x = 10 x = 10 def getX(): def getX(): return x return x def setX(n): def setX(n): x = n nonlocal x = n return (getX, setX) return (getX, setX) getX, setX = func() getX, setX = func() getX() # 10 getX() # 10 setX(20) setX(20) getX() # 10 getX() # 20
函式定義 def max(m: Int, n: Int): Int = { if (m > n) m else n } 匿名函式 val max: (Int, Int) => Int = (m: Int, n: Int) => if(m > n) m else n
函式定義 def max(m: Int, n: Int): Int = { if (m > n) m else n } 匿名函式 val max: (Int, Int) => Int = (m: Int, n: Int) => if(m > n) m else n
動態定型語言 • 型態資訊是在資料本身而不是變數 • 變數本身的型態是在執行時期運算得知, 也同一變數可以參考至各種型態的資料。 function max(m, n) { def max(m, n): if(m > n) { return m if m > n else n return m; } return n; } function(m, n) { max2 = lambda m, n: m if m > n else n if(m > n) { return m; } return n; };
靜態定型語言 • 根據資料的型態資訊,將變數及運算式進 行分類,型態資訊是在宣告的變數上 • 在執行時期變數的型態資訊無法改變,資 料只能被指定至同一種型態的變數 def max(m: Int, n: Int): Int = { if (m > n) 語法上的冗長 m else n } val max: (Int, Int) => Int = (m: Int, n: Int) => if(m > n) m else n
如果要設計callback函式… def selection(number: Array[Int], order: (Int, Int) => Boolean) { ... val o = order(a, b) … } val arr = Array(2, 5, 1, 7, 8) selection(arr, (a: Int, b: Int) => a > b) val arr = Array(2, 5, 1, 7, 8) selection(arr, (a, b) => a > b) val arr = Array(2, 5, 1, 7, 8) 類型推斷 selection(arr, (_: Int) > (_: Int)) type inference val arr = Array(2, 5, 1, 7, 8) selection(arr, _ > _)
終於輪到我登場了嗎?。。XD
目前 Java 沒有 lambda/closure List<String> list = new ArrayList<String>(); list.add("Justin"); ... Collections.sort(list, new Comparator<String>() { public int compare(String s1, String s2) { return -s1.compareTo(s2); } … }); 假設 Java 有 lambda/closure Collections.sort(list, (s1, s2) => -s1.compareTo(s2)); 借一下 Scala 的語法
目前 Java 沒有 lambda/closure • 所以無法設計 callback 函式 • 目前由 callback 物件來實現 語法上的冗長 也不僅是語法上的冗長
編譯器強迫你要加上 final 把外部res指定 public void doSome() { final int res = 10; ISome o = new ISome() { public void doIt() { 給區域變數res int result = res * 10; …. } } } 表面上…你綁定了res 事實上...編譯器只是建立一個區域變數res 所以編譯器強迫你要加上 final
就像 Python 只作「半套」?。。XD 1 18
Lambdas in Java Preview • http://stronglytypedblog.blogspot.com/2010/06/lam bdas-in-java-preview-part-1-basics.html • http://stronglytypedblog.blogspot.com/2010/07/lam bdas-in-java-preview-part-2.html • http://stronglytypedblog.blogspot.com/2010/07/lam bdas-in-java-preview-part-3.html • http://stronglytypedblog.blogspot.com/2010/07/lam bdas-in-java-preview-part-4-proposal.html • http://stronglytypedblog.blogspot.com/2010/07/lam bdas-in-java-preview-part-5-apache.html
#int(int) doubler = #(int x)(2*x); doubler.(3) int doubler(int x) { return 2 * x; } ... doubler(3); #int(int, int) sum = #(int x, int y)(x+y); int sum(int x, int y) { return x + y; }
Python max = lambda m, n: m if m > n else n max(10, 3) Scala val max: (Int, Int) => Int = (m, n) => if(m > n) m else n max(10, 3); Java #int(int, int) max = #(int x, int y) { if (x >= y) return x; else return y; }; max.(10, 3);
Scala def selection(number: Array[Int], order: (Int, Int) => Boolean) { ... val o = order(a, b) … } … selection(arr, (a, b) => a > b) Java void selection(int[] array, #boolean(int, int) order) { ... boolean o = order.(a, b); … } … selection(arr, #(int a, int b)(a > b));
目前 Java 沒有 lambda/closure List<String> list = new ArrayList<String>(); list.add("Justin"); ... Collections.sort(list, new Comparator<String>() { public int compare(String s1, String s2) { return -s1.compareTo(s2); } … }); 假設 Java 有 lambda/closure Collections.sort(list, #(String s1, String s2)(-s1.compareTo(s2)));
##int(int)(int) sum = #(int x)(#(int y)(x+y)); 傳回函式 #int(int)
新的提案 • http://cr.openjdk.java.net/~briangoetz/lamb da/lambda-state-2.html – No more function types – More type inferencing – Scala-like syntax
void selection(int[] array, #boolean(int, int) order) { ... boolean o = order.(a, b); … Function type } … selection(arr, #(int a, int b)(a > b)); public interface Order { public boolean compare(int a, int b); } void selection(int[] array, Order order) { ... boolean o = order.compare(a, b); … } SAM(Single Abstract Method) type … selection(arr, (a, b) -> {a > b}); More type inferencing Scala-like syntax
val arr = Array(10, 20, 30) var sum = 0 arr.foreach(i => sum += i) println(sum) int[] = {10, 20, 30}; int sum = 0; arr.foreach(i -> { sum += i }); System.out.println(sum); Much Better!!
我們需要? • Lambda/Closure • 類型推斷 • 單一抽象方法形態(SAM types) • 可利用現存的 API • 更多程式設計風格
林信良 http://openhome.cc caterpillar@openhome.cc

lambda/closure – JavaScript、Python、Scala 到 Java SE 7

  • 1.
    lambda/closure – JavaScript、Python、Scala 到 Java SE 7 林信良 http://openhome.cc caterpillar@openhome.cc
  • 2.
  • 3.
    Update to date •JDK 7 Features updated ! Plan B has apparently been approved – http://www.baptiste-wicht.com/2010/09/jdk-7- features-updated-plan-b-is-apparently-here/ • 2011 Java SE 7 沒有 Closure … Orz • 2012 Java SE 8 才有 Closure ... XD • 2012 世界末日才有 Closure … 囧rz
  • 4.
    議程 • lambda • closure • 動靜之間 • 沒有 lambda/closure 的 Java • Java SE 7 lambda/closure 提案
  • 5.
    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/
  • 6.
  • 7.
    function doSome(param) { // 作些事 } var doSome = function(param) { // 作些事 }; function(param) { * Function literal // 作些事 * Function 實例 }; * new Function('param', '函式本體'); * Anonymous function
  • 8.
    既然函式是物件,那麼可以作什麼? • 指定給別的變數 functionfoo(arg) { document.write(arg , '<br>'); } var zzz = foo; zzz('demo'); • 這跟樓下的是一樣的 … var foo = function(arg) { document.write(arg , '<br>'); }; var zzz = foo; zzz('demo');
  • 9.
    既然可以指定給別的變數,就可以… • 作為引數傳入函式中 functionshow(element) { document.write(element + '<br>'); } [1, 2, 3, 4, 5].forEach(show); • 這跟樓下的是一樣的 … var show = function(element) { document.write(element + '<br>'); }; [1, 2, 3, 4, 5].forEach(show);
  • 10.
  • 11.
    走訪陣列 var array =[1, 2, 3, 4, 5]; for(var i = 0; i < array.length; i++) { doucment.write(array[i] + '<br>'); } [1, 2, 3, 4, 5].forEach( function(element) { doucment.write(element + '<br>'); } );
  • 12.
    可作為引數傳入函式?那就可以設計 callback 函式.. •實作 forEach Array.prototype.forEach = function(callback) { for(var i = 0; i < this.length; i++) { callback(this[i]); } }; [1, 2, 3, 4, 5].forEach( function(element) { doucment.write(element + '<br>'); } );
  • 13.
  • 14.
  • 15.
    Closure • 文言文…. –函式物件建立時,自由變數(Free variable )綁定了當時作用範圍中的變數,使被綁定的 變數之作用範圍跟隨著被建立的函式物件 • 白話文 就是….
  • 16.
  • 17.
    這是一個區域變數 function init() { var local = 10; setInterval( function() { alert(new Date() + ': ' + local); local++; }, 自由變數(Free variable) 3000); } window.onload = init; 網頁資源載入完成後執行一次
  • 18.
    • local這樣的變數對函式實字部份的宣告 來說,稱為自由變數(Free variable) • 自由變數真正的意義,必須結合函式實字 以外的環境才可以得知
  • 19.
  • 20.
    實際的應用呢?… • 在 JavaScript中模擬私用性… function Account(money) { var balance = money; this.getBalance = function() { return balance; }; this.deposit = function(money) { if(money > 0) { balance += money; } }; } var account = new Account(1000); account.deposit(500); account.balance = 1000;
  • 21.
    var account =new Account(1000); var account = {}; Account.call(account, 1000); function Account(money) { var balance = money; * 函式是物件 this.getBalance = function() { return balance; * 物件可以擁有方法 }; this.deposit = function(money) { if(money > 0) { balance += money; } }; } Closure 綁定的是自由變數本身,而不是其值!
  • 22.
  • 23.
  • 24.
    My name isPython …. def max(m, n): return m if m > n else n print(max(10, 3)) # 顯示 10 maximum = max print(maximum(10, 3)) # 顯示 10 max = lambda m, n: m if m > n else n print(max(10, 3)) # 顯示 10
  • 25.
    函式定義 function max(m, n){ def max(m, n): if(m > n) { return m if m > n else n return m; } return n; } 匿名函式 function(m, n) { lambda m, n: m if m > n else n if(m > n) { return m; } return n; };
  • 26.
    import math 從函式傳回函式 def prepare_factor(max): # 一些建立質數表的過程,需要一些時間與資源 primes = [i for i in range(2, max) if prime[i] == 1] # 質數表 def factor(num): # 利用質數表進行因式分解的過程 while primes[i] ** 2 <= num: if num % primes[i] == 0: Closure list.append(primes[i]) num //= primes[i] else: i += 1 return factor # 傳回函式 factor = prepare_factor(1000) print(factor(100)) # 顯示 [2, 2, 5, 5]
  • 27.
    當函式是物件時 • 可以根據需要傳遞給另一個名稱參考 • 不再被動呼叫,可主動指導別的函式動作 • 流程中不同演算,設計callback函式代換 • 可以形成 Closure 綁定自由變數(資源) • 可以從函式中傳回函式
  • 29.
  • 30.
  • 31.
    def func(): def func(): x = 10 x = 10 def getX(): def getX(): return x return x def setX(n): def setX(n): x = n nonlocal x = n return (getX, setX) return (getX, setX) getX, setX = func() getX, setX = func() getX() # 10 getX() # 10 setX(20) setX(20) getX() # 10 getX() # 20
  • 32.
    函式定義 def max(m: Int,n: Int): Int = { if (m > n) m else n } 匿名函式 val max: (Int, Int) => Int = (m: Int, n: Int) => if(m > n) m else n
  • 33.
    函式定義 def max(m: Int,n: Int): Int = { if (m > n) m else n } 匿名函式 val max: (Int, Int) => Int = (m: Int, n: Int) => if(m > n) m else n
  • 34.
    動態定型語言 • 型態資訊是在資料本身而不是變數 • 變數本身的型態是在執行時期運算得知, 也同一變數可以參考至各種型態的資料。 function max(m, n) { def max(m, n): if(m > n) { return m if m > n else n return m; } return n; } function(m, n) { max2 = lambda m, n: m if m > n else n if(m > n) { return m; } return n; };
  • 35.
    靜態定型語言 • 根據資料的型態資訊,將變數及運算式進 行分類,型態資訊是在宣告的變數上 • 在執行時期變數的型態資訊無法改變,資 料只能被指定至同一種型態的變數 def max(m: Int, n: Int): Int = { if (m > n) 語法上的冗長 m else n } val max: (Int, Int) => Int = (m: Int, n: Int) => if(m > n) m else n
  • 36.
    如果要設計callback函式… def selection(number: Array[Int],order: (Int, Int) => Boolean) { ... val o = order(a, b) … } val arr = Array(2, 5, 1, 7, 8) selection(arr, (a: Int, b: Int) => a > b) val arr = Array(2, 5, 1, 7, 8) selection(arr, (a, b) => a > b) val arr = Array(2, 5, 1, 7, 8) 類型推斷 selection(arr, (_: Int) > (_: Int)) type inference val arr = Array(2, 5, 1, 7, 8) selection(arr, _ > _)
  • 37.
  • 38.
    目前 Java 沒有lambda/closure List<String> list = new ArrayList<String>(); list.add("Justin"); ... Collections.sort(list, new Comparator<String>() { public int compare(String s1, String s2) { return -s1.compareTo(s2); } … }); 假設 Java 有 lambda/closure Collections.sort(list, (s1, s2) => -s1.compareTo(s2)); 借一下 Scala 的語法
  • 39.
    目前 Java 沒有lambda/closure • 所以無法設計 callback 函式 • 目前由 callback 物件來實現 語法上的冗長 也不僅是語法上的冗長
  • 40.
    編譯器強迫你要加上 final 把外部res指定 public void doSome() { final int res = 10; ISome o = new ISome() { public void doIt() { 給區域變數res int result = res * 10; …. } } } 表面上…你綁定了res 事實上...編譯器只是建立一個區域變數res 所以編譯器強迫你要加上 final
  • 41.
  • 42.
    Lambdas in JavaPreview • http://stronglytypedblog.blogspot.com/2010/06/lam bdas-in-java-preview-part-1-basics.html • http://stronglytypedblog.blogspot.com/2010/07/lam bdas-in-java-preview-part-2.html • http://stronglytypedblog.blogspot.com/2010/07/lam bdas-in-java-preview-part-3.html • http://stronglytypedblog.blogspot.com/2010/07/lam bdas-in-java-preview-part-4-proposal.html • http://stronglytypedblog.blogspot.com/2010/07/lam bdas-in-java-preview-part-5-apache.html
  • 43.
    #int(int) doubler =#(int x)(2*x); doubler.(3) int doubler(int x) { return 2 * x; } ... doubler(3); #int(int, int) sum = #(int x, int y)(x+y); int sum(int x, int y) { return x + y; }
  • 44.
    Python max = lambdam, n: m if m > n else n max(10, 3) Scala val max: (Int, Int) => Int = (m, n) => if(m > n) m else n max(10, 3); Java #int(int, int) max = #(int x, int y) { if (x >= y) return x; else return y; }; max.(10, 3);
  • 45.
    Scala def selection(number: Array[Int],order: (Int, Int) => Boolean) { ... val o = order(a, b) … } … selection(arr, (a, b) => a > b) Java void selection(int[] array, #boolean(int, int) order) { ... boolean o = order.(a, b); … } … selection(arr, #(int a, int b)(a > b));
  • 46.
    目前 Java 沒有lambda/closure List<String> list = new ArrayList<String>(); list.add("Justin"); ... Collections.sort(list, new Comparator<String>() { public int compare(String s1, String s2) { return -s1.compareTo(s2); } … }); 假設 Java 有 lambda/closure Collections.sort(list, #(String s1, String s2)(-s1.compareTo(s2)));
  • 47.
    ##int(int)(int) sum =#(int x)(#(int y)(x+y)); 傳回函式 #int(int)
  • 48.
    新的提案 • http://cr.openjdk.java.net/~briangoetz/lamb da/lambda-state-2.html – No more function types – More type inferencing – Scala-like syntax
  • 49.
    void selection(int[] array,#boolean(int, int) order) { ... boolean o = order.(a, b); … Function type } … selection(arr, #(int a, int b)(a > b)); public interface Order { public boolean compare(int a, int b); } void selection(int[] array, Order order) { ... boolean o = order.compare(a, b); … } SAM(Single Abstract Method) type … selection(arr, (a, b) -> {a > b}); More type inferencing Scala-like syntax
  • 50.
    val arr =Array(10, 20, 30) var sum = 0 arr.foreach(i => sum += i) println(sum) int[] = {10, 20, 30}; int sum = 0; arr.foreach(i -> { sum += i }); System.out.println(sum); Much Better!!
  • 51.
    我們需要? • Lambda/Closure • 類型推斷 • 單一抽象方法形態(SAM types) • 可利用現存的 API • 更多程式設計風格
  • 52.