kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

まぎらわしい _ の意味の違い:解答編

まあ、試してみりゃすぐわかる話なんだけど、

val p = println _
p()

の方が正解。で、println(_)は(x) => println(x)のシンタックスシュガーなんだけど、xの引数の型が推論できないので、コンパイルエラーになっちゃうのであった。だから、実は

val p: String => Unit = println(_)
p("FOO")

のようにして、型を明示してやればコンパイルを通る。

一方、println _の方は、メソッドから対応する関数オブジェクトに変換するための構文であり、println _の結果にあいまい性が無ければOKなので、コンパイルを通る。あいまい性がある場合というのは、たとえば

class A {
  def f(x: Int) = x
  def f(x: Double) = x
}
val a = new A
val f = a.f _ //a.f _はあいまい

のような場合で、このとき、a.fはf(Double)を指しているのか、それともf(Int)を指しているのかがあいまいになる。

この場合、

a.f _:(Int => Int) // a.f _:Intではない

のように変換先の型を明示してやることで、コンパイルを通るようになる。