成らぬは人の為さぬなりけり

エンジニアライフをエンジョイする為のブログ

プレースホルダは意外と難しい(その2)

前回Scalaプレースホルダについて書きました。

↑の記事の後半に出てきた部分で大きな勘違いをしていたので、
訂正すると共に、学習し直したいと思います。


先日、@kmizuさんのブログで、プレースホルダについて書かれていたので、
参考にさせて頂きました。

_ と _ の違い - ((プログラミング | 形式) 言語) について書く日記


大まかに説明すると。

object.hoge _ // ①

これと

object.hoge(_) // ②

は違うよ、という事です。


上記はそれぞれ

  • ①MethodValues
  • ②Placeholder Syntax for Anonymous Functions(いわゆるプレースホルダ構文)

参考:Scala Language Specification


では、どう違うのでしょうか。
こちらの@kmizuさんのブログを読ませて頂いたのですが、
正直よく理解できませんでした。
(自分の理解力の無さを恨む、、、もっと精進せねば)


というわけで、Scala Language Specificationを見てみることにしました。
が、しかし、英語は読めない。
と思ったら、ちゃんとサンプルコードが書かれていました。


「展開されるタイミング」というのは、理解できなかったのですが、
以下の事は理解できました。

MethodValues

scala> object Foo { def foo(i:Int) = i * 3}
defined module Foo

scala> Foo.foo _
res14: Int => Int = <function1>

こうなることは、理解できていました。


では、引数が2つの場合はどうなるでしょうか?
こうなります。

scala> object Hoge { def hoge(i:Int, j:Int) = i*3 + j*3 }
defined module Hoge

scala> Hoge.hoge _
res15: (Int, Int) => Int = <function2>

2引数関数になっています。
なるほど!MethodValuesという名前は納得できます。

ex)

scala> (Hoge.hoge _)(1,2)
res16: Int = 9

scala> Hoge.hoge(_)
<console>:9: error: missing parameter type for expanded function ((x$1) => Hoge.hoge(x$1))
              Hoge.hoge(_)
                        ^
<console>:9: error: not enough arguments for method hoge: (i: Int, j: Int)Int.
Unspecified value parameter j.
              Hoge.hoge(_)
                       ^

プレースホルダ構文

ではプレースホルダ構文も書いてみます。

scala> Hoge.hoge(_,_)
res19: (Int, Int) => Int = <function2>

うん、これで2引数関数になりますね。

ex)

scala> (Hoge.hoge(_,_))(1,2)
res20: Int = 9

scala> (Hoge.hoge(_,2))(1)
<console>:9: error: missing parameter type for expanded function ((x$1) => Hoge.hoge(x$1, 2))
              (Hoge.hoge(_,2))(1)
                         ^

scala> (Hoge.hoge(1,_))(1)
<console>:9: error: missing parameter type for expanded function ((x$1) => Hoge.hoge(1, x$1))
              (Hoge.hoge(1,_))(1)
                           ^

scala> (Hoge.hoge(1,_:Int))(1)
res23: Int = 6

scala> (Hoge.hoge(1,_:Int))(2)
res24: Int = 9

一個エラーになりました。
型がわからん、と言われたので、型指定をしました。
引数全てプレースホルダ構文にする場合と違う、、、のでしょうか?
ここらへんが、展開タイミングを型チェックのタイミングが関係しているんでしょうか?

scala> var f:((Int,Int) => Int) = (_ * _)
f: (Int, Int) => Int = <function2>

scala> var f:(Int => Int) = (_ * 1)
f: Int => Int = <function1>

scala> var f:(Int => Int) = (_ + 1)
f: Int => Int = <function1>

これはOKなんですが。

うーん、まだまだ理解しきれない。。。
また調べて出直します。