その他多数
元ネタについてはよく知らんのだけど、なんか流行ってるっぽいので書いてみた。ポイントは、式の中での_がplace holderになってしまうので、通常のパラメータにはならないのをどう解決するかという所だが、implicit conversionを使うことで解決している。
object X { implicit val f :((X.type) => String) => Int = x => { println(x(X)); 0 } def /(x: X.type) = new { def /(x: X.type) = new { override def toString() = { "スケッチ" } def <(x: String): String = X + this.toString + "365 " + x } } override def toString(): String = "ひだまり" def main(args: Array[String]) { (main:Int) } def main: X.type => String = { X / _ / X < "来週も見てくださいね!" } }
追記:
とこれだけだとなんなので、これが一体何をやってるのか、もうちょっと詳しく説明してみることにする。
まず、
object X { ... }
で、Xがオブジェクトとして使えるように=式の中で値として使えるようにしている。
次に、
def /(x: X.type) = new { ... }
だが、これは、Xに対して、2項の/演算子を定義している。このとき、引数の型がX.typeとなっているが、これは、Xと同じインスタンス(であることが保証されている)しか代入できない型、という意味。実は必要無いのだけど、使ってみたかっただけという。あと、
new { ... }
はJavaにおける匿名クラスみたいなもので、無名のクラスの新しいインスタンスを生成することができる。継承元のクラスを明記していないが、省略した場合、AnyRefを継承元として指定したのと同じことになる。
X / _ / X < "来週も見てくださいね!"
は、_がなければ、単なる演算子呼び出し(=メソッド呼び出し)のチェインだが、実は、式の中で現れる_は無名関数の仮引数への参照のplace holderとなっており、そのため、上記の式は、
(x) => X / x / X < "来週も見てくださいね!"
のシンタックスシュガーとなる。
さて、ここで問題なのは、
X / _ / X < "来週も見てくださいね"
という式が無名関数を返す式になってしまうため、文字列を出力という副作用を起こすことができないという点だが、これは、最初に書いたように、implicit conversionによって無理やり副作用を挿入する事によって解決した(単純に、main()から返って来た無名関数を呼び出しても良いのだけど、それだとScalaっぽさがあまり出ないし、面白みが無い)。具体的には、mainから返って来る無名関数の型はX.type => Stringになるが、main:Intによって、Int型に「アップキャスト」することで、X.type => StringからIntへのimplicit conversionが挿入されるようにした(型はIntじゃなくても、適当な型ならなんでも良かったのだが、とりあえず一番お手軽なIntを選んだ)。