CLOVER🍀

That was when it all began.

Scala/Clojure/Groovyで即時関数

あまり意味のない小ネタです。

JavaScriptで使われるテクニックとして、即時関数というものがあると思います。こういうやつですね。
immediate_func.js

(function (firstName, lastName) {
    println("Hello! [" + firstName + " " + lastName + "]");
})("Taro", "Tanaka")

実行すると

$ jrunscript -f immediate_func.js 
Hello! [Taro Tanaka]

ちなみに、jrunscriptというのはJDKに同梱されているJavaScriptの実装(Rhino)ですね。

$ jrunscript -q
Language ECMAScript 1.8 implemention "Mozilla Rhino" 1.7 release 3 PRERELEASE

なんか書いてみたくなったので、ScalaClojure/Groovyでこれを書いてみることにしました。…そもそも、JavaScriptには関数以外にスコープの概念がないので、他の言語で書き換えてもあまり使い道はないと思うのですが。ま、いっかと。

Scala

いきなり、波括弧でスコープを切ってしまいました…。

{
  (firstName: String, lastName: String) =>
    println("Hello! [%s %s]".format(firstName, lastName))
}.apply("Taro", "Tanaka")

スコープの最後に評価されるのが関数リテラルなので、結果値が関数オブジェクトになります。これに対して、applyしてるって感じですね。残念ながら、

{
  (firstName: String, lastName: String) =>
    println("Hello! [%s %s]".format(firstName, lastName))
}("Taro", "Tanaka")

という表記はコンパイルエラーになりました…。

Clojure

すごい単純で、定義した無名関数にそのまま引数を渡すだけで呼び出せます。

((fn [first-name last-name]
   (println (format "Hello! [%s %s]" first-name last-name)))
 "Taro" "Tanaka")

冗長に書くと

(.invoke (fn [first-name last-name]
   (println (format "Hello! [%s %s]" first-name last-name)))
 "Taro" "Tanaka")

といった感じでしょうか。Clojureのリスト評価って、最初の要素が関数オブジェクトだとどうもinvokeが暗黙的に実行されていると思うのですが…。

Groovy

1番それっぽいです。

{ firstName, lastName ->
    println("Hello! [${firstName} ${lastName}]")
}("Taro", "Tanaka")

JavaScriptも、これくらい簡単に無名関数が定義できたらいいのになぁと思います。毎度毎度、functionが面倒…。

とまあ、こんな感じです。やっぱり、これらの言語では使う機会はないと思いますが…。