『Scala by Example』第5章_ファーストクラス関数

2625 ワード

Scalaの関数は「ファーストクラス関数」(first-class value)です.他の値のように、関数はパラメータとして渡されてもよいし、結果として返されてもよい.この場合の関数は「高次関数」(higher-order functions)と呼ばれます.
5.1匿名関数(anonymous functions)
匿名関数は名前のない関数です.例:(x:Int,y:Int)=>x*y.ここで注意したいのは、実際にコードを書くときに「=>」の前にこの関数の戻りタイプを加えると、(x:Int,y:Int):Int=>x*yなど、かえってエラーが発生することです.なぜなら、一般的にScalaコンパイラは匿名関数パラメータのタイプを自動的に推定するので、コンパイラにとって戻りタイプが余計であるため、戻りタイプを省略することができるからです.もちろん、匿名関数のパラメータが1つしかない場合は、そのタイプを省略することもできます.
匿名関数はScala言語に必要な要素(essential elements)ではありません.実際、匿名関数は次のように等価です.
(x1: T1 , ... , xn : Tn) => E

<=>  
{def f(x1 : T1 , ... , xn :Tn) = E ; f _}

ここでの関数名fは,コード内の他の場所では使用できない.匿名関数は「文法糖」(syntactic sugar)5.2コリー化(currying)であると一般的に言われている.
次のコードを例にとります.
def sum(f :Int => Int) : (Int , Int) => Int = {

  def sumF(a : Int , b : Int) : Int = 

    if (a >b ) 0 else f(a) + sumF( a + 1 , b)

  sumF

}

この形式ではsumは別の関数を返す関数であり,返される関数名はsumFである.今ではこの関数も前の関数の仕事を完成することができて、それはa,bの2つのパラメータを持って、sumのパラメータfをaとbに適用して、それからそれらを加えて結果を得ることができます.定義した関数を使用して、defで次のように定義できます.
def sumInts = sum(x => x)

def sumSquares = sum( x => x * x)

def sumPowersOfTwo = sum(powerOfTwo)

または、値の定義もできます.
val sumInts = sum( x => x)

val sumSquares = sum( x => x * x)

val sumPowersOfTwo = sum(powerOfTwo)

このように定義すると、組み込み関数のように使用できます.
scala > sumSquares(1 , 10) +sumPowersOfTwo(10 , 20)

このような状況はよくあるので、Scalaには特別な文法があります.次に例を示します.
def sum(f : Int => Int)(a : Int , b : Int) : Int = 

  if ( a > b ) 0 else f(a) + sum(f)(a + 1 , b )

5.3 fixed pointsを見つけます.この固定点を再帰的に見つけることです以前の平方根を求める例に似ています.実際に例から分かるように,コリー化は1つの関数を深い抽象化することができ,これはコード多重化に便利である.
5.4総括
以前の章から,計算の汎用的な方法を導入できるため,関数が必要な抽象であることが分かった.この章では,これらの抽象が高次関数に結合され,より深い抽象を創造できることを示した.プログラマーとして、抽象とコード多重化の機会を探すべきです.最も可能性の高い抽象は必ずしも最良ではないが,抽象技術が重要であることを知っているので,適切な場所で抽象を用いるべきである.
5.5今まで見た文法要素
  • 要素をスペースで区切ることに注意してください.x+(-y)を表すには、x+と-yの間に
  • のスペースを付ける必要があります.
  • $は、コンパイラに識別子(identifiers)を生成するための予約語です.ソースコードで
  • を使用するべきではありません.
    その後、いくつかのタイプ(type)、定義(definitions)などについて話します.これらは『Scalaプログラミング』でも述べられています.基本的な内容です.省略する.