会社の若人向けの勉強会にゲリラで参加してる。it変数も面白いけど、資料を読んでいると非常に面白い機能がバリバリあることがわかって楽しい。
- カリー化
- クロージャ
- 高階関数
とかほとんどPythonとかJavaScriptみたいな擬似関数型言語の機能も持っていて興味深い。
のでいろいろ検証コードを書いてみて社内MLに投げつけたり、チートシートを探してきて配布したり。
Groovyのいやなところ
そんなGroovyのいやなところは、
- Windows環境だとjLineが利いてない感じで、コード補完もシンタックスハイライトも利かないのがむかつく
- groovyshがよくハングアップするのもむかつく
カリー化
素敵だ。
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