Groovy

会社の若人向けの勉強会にゲリラで参加してる。it変数も面白いけど、資料を読んでいると非常に面白い機能がバリバリあることがわかって楽しい。

とかほとんどPythonとかJavaScriptみたいな擬似関数型言語の機能も持っていて興味深い。
のでいろいろ検証コードを書いてみて社内MLに投げつけたり、チートシートを探してきて配布したり。

Groovyのいやなところ

そんなGroovyのいやなところは、

  • Windows環境だとjLineが利いてない感じで、コード補完もシンタックスハイライトも利かないのがむかつく
  • groovyshがよくハングアップするのもむかつく

http://groovy.codehaus.org/Groovy+Shell

カリー化

素敵だ。

groovy:000> li = ['red','blue','yellow','green','black']
===> [red, blue, yellow, green, black]
groovy:000> fl = []
===> []
groovy:000> def printColor(color) {
groovy:001>     println 'you choiced ' + color
groovy:002> }
===> true
groovy:000> printColor('red')
you choiced red
===> null
groovy:000> for (i in li) {
groovy:001>     fl.add printColor.curry(i)
groovy:002> }
===> null
groovy:000> fl
===> [org.codehaus.groovy.runtime.CurriedClosure@b51c29, org.codehaus.groovy.runtime.CurriedClosure@4bf53e, org.codehaus.groovy.runtime.CurriedClosure@d1e
s.groovy.runtime.CurriedClosure@c68a98, org.codehaus.groovy.runtime.CurriedClosure@b51404]
groovy:000> for (f in fl){
groovy:001>     f()
groovy:002> }
you choiced red
you choiced blue
you choiced yellow
you choiced green
you choiced black
===> null

クロージャとレキシカルスコープ

この挙動はちょっとシックリこないけど、これがレキシカルスコープってことかー。
PythonもJSも同じ感じの挙動だった気がするから、たんに自分の理解が足りてないだけだけど。

groovy:000> fl2 = []
===> []
groovy:000> for (i in li) {
groovy:001>     fl2.add {printColor(i)}
groovy:002> }
===> null
groovy:000> fl2
===> [groovysh_evaluate$_run_closure1@988707, groovysh_evaluate$_run_closure1@1c8ef56, groovysh_evaluate$_run_closure1@d90453, groovysh_evaluate$_run_closure1@1ab11b0, groovysh_evaluate$_run_closure1@165b7e]
groovy:000> for (f in fl2) {
groovy:001>     f()
groovy:002> }
you choiced black
you choiced black
you choiced black
you choiced black
you choiced black
===> null

it

groovy:000> li = ['red','blue','yellow','green','black']
===> [red, blue, yellow, green, black]
groovy:000> l = [:]
===> {}
groovy:000> li.each{ l[it]= {println "called $it"}}
===> [red, blue, yellow, green, black]
groovy:000> l.red()
called null
===> null

これ、itをそのまま使おうとしてるけど、関数内でitを書くと暗黙で引数として扱われるからダメなんですね。
こうなっちゃう。

groovy:000> l.red('a')
called a
===> null

んじゃあ、一時引数に入れればいいのかというと、

groovy:000> li.each{ tmp = it; l[tmp]= {println "called $tmp"}}
===> [red, blue, yellow, green, black]
groovy:000> l.red()
called black
===> null
groovy:000> l.yellow()
called black
===> null

これも上のパラグラフに書いたのと一緒。
クロージャのオブジェクト自体は同じものを指しているから、最後に評価したblackが入ってる。
やっぱりこれも、まだしっくりきてない。
じゃあ、どうやるのがいいかと言ったら、やっぱりカリー化なのかなぁ。

groovy:000> li.each{ tmp = it; l[tmp]= {hoge -> println "called $hoge"}.curry(tmp)}
===> [red, blue, yellow, green, black]
groovy:000> l.red
===> org.codehaus.groovy.runtime.CurriedClosure@aea710
groovy:000> l.red()
called red
===> null
groovy:000> l.blue()
called blue
===> null