0Pricing
Scala for Backend Engineering & Functional Programming · レッスン

高階関数とカリー化

高階関数やカリー化などの高度な関数型概念を学び、柔軟で再利用可能なコードを作成します。

「高階関数とカリー化」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン2/3です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全3レッスンが含まれています。

高階関数を使いこなす

レッスン2へようこそ!関数型プログラミングでは、関数は強力な存在です。関数は値を計算するためだけのものではなく、ほかのデータと同じように扱うこともできます。

つまり、関数をほかの関数の引数として渡したり、関数の結果として返したりできます。このような処理を行う関数を、高階関数(Higher-Order Function、HOF)と呼びます。

  • HOFは、1つ以上の関数を引数として受け取ります。
  • HOFは、結果として関数を返します。
  • または、その両方を行います。

HOFの実践:`map`

Scalaで最もよく使われるHOFの1つがmapです。指定した関数を各要素に適用してコレクションを変換し、新しいコレクションを返します。

次の簡単な例を実行してみましょう。

object Main {
  def main(args: Array[String]): Unit = {
    val numbers = List(1, 2, 3)
    val doubledNumbers = numbers.map(x => x * 2)
    println(s"Original: $numbers")
    println(s"Doubled: $doubledNumbers")
  }
}

HOFの実践:`filter`

もう1つ便利なHOFがfilterです。指定した条件(booleanを返す関数)を満たす要素をコレクションから選び出し、新しいコレクションを作成します。

filterを使って偶数を見つける方法は次のとおりです。

object Main {
  def main(args: Array[String]): Unit = {
    val allNumbers = List(1, 2, 3, 4, 5, 6)
    val evenNumbers = allNumbers.filter(x => x % 2 == 0)
    println(s"All: $allNumbers")
    println(s"Even: $evenNumbers")
  }
}

独自のHOFを定義する

組み込みのHOFだけを使う必要はありません。ほかの関数をパラメーターとして受け取る独自の関数も定義できます。関数型の構文は(InputType => ReturnType)です。

次の例では、Intと、Intを受け取ってIntを返す別の関数opを受け取る関数applyOperationを定義しています。

object Main {
  // A HOF that applies an operation to a number
  def applyOperation(x: Int, op: Int => Int): Int = {
    op(x)
  }

  def main(args: Array[String]): Unit = {
    val result = applyOperation(10, _ * 3) // Pass an anonymous function
    println(s"Result of 10 * 3: $result")

    val anotherResult = applyOperation(7, _ + 5)
    println(s"Result of 7 + 5: $anotherResult")
  }
}

無名関数と省略記法

HOFに関数を渡すときは、無名関数(ラムダとも呼ばれます)をよく使います。Scalaには、無名関数を簡潔に記述する方法があります。

  • x => x * 2:無名関数を完全な形で記述したものです。
  • _ * 2:引数が1つの無名関数の省略記法です。

どちらもよく使われる書き方で、コードを短く読みやすくできます。

object Main {
  def main(args: Array[String]): Unit = {
    val numbers = List(10, 20, 30)

    // Using full anonymous function syntax
    val dividedByTwo = numbers.map(x => x / 2)
    println(s"Divided by two: $dividedByTwo")

    // Using shorthand `_` syntax
    val plusOne = numbers.map(_ + 1)
    println(s"Plus one: $plusOne")
  }
}

カリー化の導入

カリー化とは、複数の引数を受け取る関数を、それぞれが1つの引数を受け取る関数の並びに変換する手法です。

この名前は、論理学者のHaskell Curryに由来します。Scalaでは、複数のパラメーターリストを持つ関数は自動的にカリー化されます。

f(arg1, arg2)の代わりに、f(arg1)(arg2)と記述します。

カリー化の例:複数のパラメーターリスト

カリー化がどのように機能するか見てみましょう。addが引数を2つの異なるパラメーターリストで受け取っている点に注目してください。

これにより、関数を部分適用し、一部の引数を固定して新しい関数を作成できます。

object Main {
  // A curried function with two parameter lists
  def add(a: Int)(b: Int): Int = {
    a + b
  }

  def main(args: Array[String]): Unit = {
    // Call the function normally
    println(s"5 + 3 = ${add(5)(3)}")

    // Partially apply the first argument
    val addFive = add(5)_ // `_` tells Scala to treat it as a partially applied function
    println(s"5 + 10 = ${addFive(10)}")
    println(s"5 + 20 = ${addFive(20)}")
  }
}

カリー化の利点

なぜカリー化を使うのでしょうか。関数型プログラミングでは、次のような利点があります。

  • 部分適用:一部の引数を固定して、関数の特化版を作成できます。コードの再利用性が高まります。
  • 関数合成:カリー化された関数は、ほかの関数と合成しやすいことがよくあります。
  • 型推論:特に複雑なジェネリック型を扱う場合に、Scalaの型推論に役立つことがあります。

カスタムロガーのカリー化

同じ中核ロジックを使いながら、レベル(例:INFO、ERROR)ごとに異なるロギング関数を作成したいとします。カリー化はこの用途に最適です。

汎用的なlog関数を定義し、それを部分適用して特定のロガーを作成できます。

object Main {
  def log(level: String)(message: String): Unit = {
    println(s"[$level] $message")
  }

  def main(args: Array[String]): Unit = {
    // Create specialized loggers using partial application
    val infoLogger = log("INFO")_
    val errorLogger = log("ERROR")_

    infoLogger("User logged in successfully.")
    errorLogger("Failed to connect to database!")
  }
}

理解度チェック:HOFとカリー化

次のScalaコードを考えてみましょう。

def calculate(x: Int)(y: Int, op: (Int, Int) => Int): Int = {
  op(x, y)
}

val add = (a: Int, b: Int) => a + b
val multiply = (a: Int, b: Int) => a * b

val result1 = calculate(10)(5, add)
val result2 = calculate(2)(3, multiply)

result1とresult2の値はいくつになるでしょうか。

復習:HOFとカリー化

よくできました!関数型プログラミングにおける、2つの強力な概念を学びました。

  • 高階関数(HOF):ほかの関数を引数として受け取ったり、結果として返したりできる関数です。mapやfilterのように、柔軟で再利用可能なコードを実現します。
  • カリー化:複数の引数を持つ関数を、それぞれが1つの引数を受け取る関数の並びに変換する手法です。部分適用や特化した関数の作成に適しています。

これらの概念は、表現力が高くモジュール化されたScalaコードを書くための基本です。

よくある質問

「高階関数とカリー化」レッスンは無料ですか?

はい。「高階関数とカリー化」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全3レッスンが含まれています。

「高階関数とカリー化」で何を学びますか?

高階関数やカリー化などの高度な関数型概念を学び、柔軟で再利用可能なコードを作成します。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/3です。

「高階関数とカリー化」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?

はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 第一級値としての関数
  2. 高階関数とカリー化
  3. 不変性と副作用
← Scala for Backend Engineering & Functional Programmingに戻る