2010-10-03

apply and procedure

你的程式語言可以這樣做嗎?  讀完以後,用 Tcl 實驗匿名函式能力以後的結果。


寫程式的時候,你注意到有二段 code 一模一樣,除了一個反覆呼叫一個叫 BoomBoom 的函數,另一個反覆呼叫一個喚作 PutInPot 的。

puts "get the lobster"
PutInPot "lobster"
PutInPot "water"

and

puts "get the chicken"
BoomBoom "chicken"
BoomBoom "coconut"

現在你需要一個辦法,使得你可以將一個函數用作另一個函數的參數。這是個重要的能力,因為你更容易將常用的程式碼收藏在一個函數內。而 Tcl 所具有的彈性讓我們可以這樣做:

proc Cook {arg1 arg2 func} {
   puts -nonewline "get the "
   puts $arg1
   
   $func $arg1
   $func $arg2
}

所以我們就可以這樣用:

Cook  "lobster" "water" "PutInPot"
Cook  "chicken" "coconut" "BoomBoom" 

這樣就可以將函數作為參數了。

假設你未定義 PutInPot 或 BoomBoom 這些函數。如果能直接將它寫進一行內,不是比在其他地方宣告它們更好嗎?

proc Cook {arg1 arg2 func} {
   puts -nonewline "get the "
   puts $arg1
   
   set result [info procs $func]

   if {[string length $result] == 0} {
    apply $func $arg1
    apply $func $arg2
   } else {
    $func $arg1
    $func $arg2
   }
}

所以:

Cook "chicken" "coconut" {{food} { 
    puts -nonewline "BoomBoom --- "
    puts $food}
}

這樣是不是很方便?我建立函數時,甚至不用考慮怎麼命名,直接拿起它們,丟到一個函數內就可以了。

apply - Apply an anonymous function
apply func ?arg1 arg2 ...?

其中的 func 定義了參數和 procedure 要執行的東西(procedure body),思考一下 Tcl 如何定義 procedure,就知道該怎麼做:

proc anonymous_function {food} {
    puts -nonewline "BoomBoom --- "
    puts $food}
}

所以

Cook "chicken" "coconut" {{food} {
    puts -nonewline "BoomBoom --- "
    puts $food
  }
}