Scala入門 その3

Scalaスケーラブルプログラミング[第2版]をゆっくり読み進める。

とりあえず4~8章までは読んだ。
4~7章は特に面白いと思える箇所はなかった。
(for式は面白そうだが、詳細な解説は別章となっているのがなぁ。。。)

8章はScalaの関数の機能の簡単な解説。
Scalaは関数型プログラミングをサポートしている言語なので
無名関数、部分適用、クロージャといった機能がScalaでどのように
提供されているかといった説明になる。
他の関数型言語を触ったこともあるので目新しい感じはしなかった。
なのでそれ以外についてメモ。


8章ではScalaの関数の特殊な形式として以下の機能の説明があった。

  • 連続パラメータ(可変長引数)をとる関数
  • 名前付き引数
  • 関数パラメータのデフォルト値の設定方法


Scalaの関数パラメータは型の後に*(アスタリスク)をつけると
そのパラメータは*をつけた型のArray(=連続パラメータ(可変長引数))として関数に渡される。

def echo(args: String*) = { ... } // <- echo関数のargsは関数内ではArray[String]

echo("hello", "world")          // 引数の数は可変なのでこれもOK。
echo("hello", "world", "aaaa", "cccc")  // これもOK。

ただし、連続パラメータを受け取る関数にその型のArrayをパラメータとして渡そうとしてもコンパイルエラーになる。連続パラメータをとる関数にArrayを渡す場合、Arrayの後ろに_*(アンダーバーとアスタリスク)を設定する必要がある。

echo(Array("hello", "world")) // NG:これはコンパイルエラー

echo(Array("hello", "world"): _*) // OK


名前付き引数は関数実行時に対象の関数のパラメータに定義された順番とは異なる順番でパラメータを渡すこと。

def calc(x: Int, y: Int, z: Int) = { x + (y * z) }

// 通常の関数実行
// パラメータx, y, zは関数に渡された順番で束縛される
calc(1, 2, 3)

// 名前付き引数での関数実行
// パラメータに値を束縛する順番も変えられる
calc(z = 1, x = 2, y = 3) // 名前で指定されたパラメータの値を束縛
calc(2, y = 2, z = 3)     // 2はxに束縛。


Scalaでは関数パラメータにデフォルト値を指定できる。
デフォルト値は関数パラメータの型の後に[= デフォルト値]のように書く。
関数実行時に値が束縛されないパラメータはデフォルト値が使用されるようだ。

def calc(x: Int = 10, y: Int) = { x * y }  // xのデフォルト値は10

scala> calc(y = 10)
res17: Int = 100

ただし、上記のcalc関数実行は名前付き引数でyに値を束縛することを明示しないとコンパイルエラーになった。デフォルト値が設定されてない方に勝手に束縛とかはないっぽい。

scala> calc(10)
<console>:9: error: not enough arguments for method calc: (x: Int, y: Int)Int.
Unspecified value parameter y.
              calc(10)

と思ったら、パラメータの順番を変えずにyの方にデフォルト値を設定するようにした場合は名前付き引数を使用しなくてもxの方に値が束縛された。ふ~む...

scala> def calc(x: Int, y: Int = 10) = { x * y } // xではなくyのデフォルト値を指定
calc: (x: Int, y: Int)Int

scala> calc(10)  // 名前付き引数なし
res18: Int = 100


8章の最後でScalaでの末尾再帰について書かれていた。
Scalaの末尾再帰の最適化は色々制約があるようだ。
これは後で色々試してみようと思う。


とりあえず今日はここまで。