初めに言っておくと、これはマジなクイズではありません。実際にScalaのプレースホルダー構文を使う上でここまで詳細な挙動を知る必要はありませんし、知る必要のあるようなプレースホルダー構文の使い方をしていたら、それはおそらく誤った使い方です。ただ、Scalaのプレースホルダー構文の特性を示すためにクイズ形式にしてみました。
無名関数のためのプレースホルダー構文を使ったScalaプログラムの断片について、以下の問いに答えてください。
1. =の右辺の展開結果が全く同じになるコード例のグループを全て列挙してください(e.g, (1-1,1-2), (2-2,2-3))。展開結果が全く同じというのは、評価結果が同じになるという意味ではなく、展開した式の形が同じになることを指しています。
たとえば、(x:Int) => x + x
と(x) => x + x
のような形は、明示的な型指定によって木の形が同じでないので、異なるものとみなします。一方、最終的に推論される関数の型が違っても、プレースホルダー構文を展開した時点での右辺の式の形が同じ場合は同じものとみなします。たとえば、val a: String => String = x => x
と、val b: Int => Int = x => x
の右辺は同じものとみなします。
2. コンパイルできるコード例を全て抽出してください(e.g. 1-2, 1-3)。
3. コンパイルできないコード例を二つ以上抽出し、その理由を簡単に述べてください。
なお、処理系は動かさずに、Scala Language Specificationだけから結果を予測してください*1。正解と解説は明日書く…かもしれないです。
- 1-1
val add = _ + _
- 1-2
val add = (_:Int) + (_:Int)
- 1-3
val add: (Int, Int) => Int = _ + _
- 1-4
val add = _.+(_)
- 1-5
val add: (String, String) => String = _ + _
- 2-1
val lst = List(1, 2, 3).map(_ + 1)
- 2-2
val lst = List(1, 2, 3).map(_.+(1))
- 2-3
val lst = List(1, 2, 3).map((_:Int) + 1)
- 2-4
val lst = List(1, 2, 3).map((_:Int).+(1))
- 3-1
val lst2 = List(1, 2, 3).map(_)
- 3-2
val lst2 = List(1, 2, 3).map((_:Int))
- 3-3
val lst2 = List(1, 2, 3).map((_:Int => Int))
- 3-4
val lst2 = List(1, 2, 3).map(+(_))
- 3-5
val lst2: List[Int] = List(1, 2, 3).map(_)
- 3-6
val lst2 = List(1, 2, 3).map(identity(_))
- 4-1
val idfun = _;
- 4-2
val idfun = identity(_)
- 4-3
val idfun = identity(_:Int)
- 4-4
val idfun = (identity(_:Int))
- 4-5
val idfun = identity(identity(_))
*1:ヒント:p.94とChapter 6 Expressions冒頭