高階関数とカリー化
高階関数やカリー化などの高度な関数型概念を学び、柔軟で再利用可能なコードを作成します。
「高階関数とカリー化」は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フィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 第一級値としての関数
- 高階関数とカリー化
- 不変性と副作用