部分適用・部分関数・カリー化

1. 部分適用された関数(partially applied function)

事前に引数の一部を適用した関数の事を『部分適用された関数』呼びます。

def greeting(timing:String, opponent:String):String = {
  timing match {
   case "morning"  => s" おはようございます、$opponent さん!" // s"XXX $変数 " は string interpolation と言う機能で、変数を文字列の中で使う機能です。
   case "afternoon"  => s" こんにちは、$opponent さん!"
   case "Night"   => s" こんばんは、$opponent さん!"
  }
}

汎用的な挨拶の関数があった場合に、それを特定挨拶用の関数として変数に代入する事ができます。

val goodMorning = greeting("morning", _:String)

goodMorning のように、一部の引数の値を適用して、一部の引数(XXXさん)を後から適用するために、朝だけの挨拶用の関数オブジェクトを宣言できます。 以下のように利用することができます。

goodMorning("Sam")
// " おはようございます、Sam さん!"

2. 部分関数(partial function)

『部分適用した関数』と似た文言の『部分関数』と呼ばれる関数オブジェクトがあります。 こちらは、ある集合に対して一部を適用して結果を返すために使います。

val partialFunc: PartialFunction[(String, String), String] = {
  case (timing:String,opponent:String) if timing == "morning" => s" おはようございます、$opponent さん!"
  case (timing:String,opponent:String) if timing == "afternoon" => s" こんにちは、$opponent さん!"
}

PartialFunction 型の関数を定義しています。 timing が “morning” か “afternoon”の場合のみ挨拶を返す部分関数です。

val greetList = List(("morning","Sam"),("afternoon","Bob"),("Night","Jon"))
greetList.collect(partialFunc)
// List(" おはようございます、Sam さん!", "こんにちは、Bob さん!")

List で宣言した一覧に、partialFunc (朝と午後の挨拶のみ)を適用すると、 “Night”は部分関数に定義されていないため抽出されません。

3.カリー化

カリー化とは、一つの引数をとる関数を連続して呼び出す関数のことです。 下の例ではカリー化されておらず、引数を複数に分割しただけです。

def greetingNotCurry(timing:String)(opponent:String):String = {
  timing match {
   case "morning" => s" おはようございます、$opponent さん!" // s"XXX $変数 " は string interpolation と言う機能で、変数を文字列の中で使う機能です。
   case "afternoon" => s" こんにちは、$opponent さん!"
   case "Night" => s" こんばんは、$opponent さん!"
  }
}

関数オブジェクトに一つ目の引数を指定して、アンダースコアをつける事でカリー化できます。

val greetCurry = FuncCurry.greetingNotCurry("morning")_
// greetCurry : String => String =  <function1>
// こんな感じで第2引数を指定して関数を呼べます。
greetCurry("Sam")

上記例では、個別にカリー化しましたが、3つの引数が定義された関数を curried メソッドでカリー化にもできます。

def greetingNotCurry(timing:String,opponent:String, end:String):String = {
  timing match {
   case "morning" => s" おはようございます、$opponent さん! $end" // s"XXX $変数 " は string interpolation と言う機能で、変数を文字列の中で使う機能です。
   case "afternoon" => s" こんにちは、$opponent さん! $end"
   case "Night" => s" こんばんは、$opponent さん! $end"
  }
}

// これでカリー化
val greetCurry = (greetingNotCurry _).curried
// greetCurry : String => (String => (String => String)) =
// こんな感じの関数チェーン(丸括弧と "=>")の連続に!
( (greetCurry("morning") )("Elly") )("今日は暖かいですね!")

このように返された関数に引数を渡して、更に返された関数に引数を渡すといった事が可能です。