前章:ミックスインを使用したクラス合成


  • 関数を引数として受け取るメソッドと関数、あるいは関数を返す関数の両方に対して高階関数という
  • 下記はScalaのコレクションでよく利用される高階関数mapの例
val salaries = Seq(20_000, 70_000, 40_000)
val doubleSalary = (x: Int) => x * 2
val newSalaries = salaries.map(doubleSalary) // List(40000, 140000, 80000)
  • コードを短縮するために、関数を匿名化して直接mapに引数として渡すこともできる
    • コンパイラがxの型を推論しているので、Int型の宣言は不要
val salaries = Seq(20_000, 70_000, 40_000)
val newSalaries = salaries.map(x => x * 2) // List(40000, 140000, 80000)
  • xの代わりに_を使用することで、コードを更に簡略化できる
val salaries = Seq(20_000, 70_000, 40_000)
val newSalaries = salaries.map(_ * 2) // List(40000, 140000, 80000)

メソッドを関数に強制変換する

  • Scalaのコンパイラはメソッドを高階関数に渡すと、関数に強制変換させる
case class WeeklyWeatherForecast(temperatures: Seq[Double]):
 
  private def convertCtoF(temp: Double) = temp * 1.8 + 32
 
  def forecastInFahrenheit: Seq[Double] = temperatures.map(convertCtoF)

関数を受け入れる関数

  • 高階関数を使用する理由の一つに、冗長なコードを削減することにある
object SalaryRaiser:
	// map呼び出しが冗長
  def smallPromotion(salaries: List[Double]): List[Double] =
    salaries.map(salary => salary * 1.1)
 
  def greatPromotion(salaries: List[Double]): List[Double] =
    salaries.map(salary => salary * math.log(salary))
 
  def hugePromotion(salaries: List[Double]): List[Double] =
    salaries.map(salary => salary * salary)
    
object SalaryRaiser:
	// promotionとして高階関数に抽出してDRYを実現させる
  private def promotion(salaries: List[Double], promotionFunction: Double => Double): List[Double] =
    salaries.map(promotionFunction)
 
  def smallPromotion(salaries: List[Double]): List[Double] =
    promotion(salaries, salary => salary * 1.1)
 
  def greatPromotion(salaries: List[Double]): List[Double] =
    promotion(salaries, salary => salary * math.log(salary))
 
  def hugePromotion(salaries: List[Double]): List[Double] =
    promotion(salaries, salary => salary * salary)

関数を返す関数

  • 関数を返す関数を定義することもできる
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String =
  val schema = if ssl then "https://" else "http://"
  (endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
 
val domainName = "www.example.com"
def getURL = urlBuilder(ssl=true, domainName)
val endpoint = "users"
val query = "id=1"
val url = getURL(endpoint, query)
println(url) // https://www.example.com/users?id=1

次章:[[]]