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

代数的データ型

ドメインをモデル化します。

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

ADTとは

代数的データ型(ADT)は、ほかの型を組み合わせて作る型です。Scalaでは、sealed traitとcase classおよびcase objectのバリアントを使ってADTをモデル化します。

ADTを使うと、ドメインデータの構造を正確に表現できます。

Sum型

sum型は、値が複数の選択肢のうちの1つであること(OR)を表します。信号機は、赤OR黄OR青です。

これをsealed traitと複数のバリアントで表現します。

sealed trait Light
case object Red extends Light
case object Yellow extends Light
case object Green extends Light
object Main {
  def main(args: Array[String]): Unit = {
    val l: Light = Yellow
    println(l)
  }
}

Product型

product型は、値が複数のフィールドを組み合わせたものであること(AND)を表します。点はxとyを持ちます。

case classはproduct型です。

case class Point(x: Int, y: Int)
object Main {
  def main(args: Array[String]): Unit = {
    val p = Point(3, 4)
    println(s"${p.x} and ${p.y}")
  }
}

Sum型とProduct型の組み合わせ

実際のADTでは、両方を組み合わせます。つまり、sealed trait(sum型)のバリアントがcase class(product型)になります。

ここでは、Shapeが、半径を持つCircleまたは幅と高さを持つRectangleのいずれかです。

sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(w: Double, h: Double) extends Shape
object Main {
  def main(args: Array[String]): Unit = {
    val s: Shape = Rectangle(3, 4)
    println(s)
  }
}

ADTを操作する

ADTは、バリアントに対してパターンマッチングを行って処理します。各分岐で1つの図形を処理します。

sealed trait Shape
case class Circle(radius: Double) extends Shape
case class Rectangle(w: Double, h: Double) extends Shape
object Main {
  def area(s: Shape): Double = s match {
    case Circle(r)       => 3.14159 * r * r
    case Rectangle(w, h) => w * h
  }
  def main(args: Array[String]): Unit = {
    println(area(Circle(2)))
    println(area(Rectangle(3, 4)))
  }
}

ドメインをモデル化する

ADTを使うと、無効な状態を表現できなくなります。支払い方法を、有効な選択肢だけからなる閉じた集合としてモデル化します。

sealed trait PaymentMethod
case class CreditCard(number: String) extends PaymentMethod
case class BankTransfer(iban: String) extends PaymentMethod
case object Cash extends PaymentMethod
object Main {
  def main(args: Array[String]): Unit = {
    val m: PaymentMethod = Cash
    println(m)
  }
}

再帰的なADT

ADTは自分自身を参照できます。これにより、木やリストをモデル化できます。ここでは単純な二分木を示します。

sealed trait Tree
case object Leaf extends Tree
case class Node(value: Int, left: Tree, right: Tree) extends Tree
object Main {
  def main(args: Array[String]): Unit = {
    val t: Tree = Node(1, Leaf, Node(2, Leaf, Leaf))
    println(t)
  }
}

再帰的なADTを畳み込む

再帰とマッチングを組み合わせると、構造全体を処理できます。ここでは、木のすべての値を合計します。

sealed trait Tree
case object Leaf extends Tree
case class Node(value: Int, left: Tree, right: Tree) extends Tree
object Main {
  def sum(t: Tree): Int = t match {
    case Leaf            => 0
    case Node(v, l, r)   => v + sum(l) + sum(r)
  }
  def main(args: Array[String]): Unit = {
    val t = Node(1, Node(2, Leaf, Leaf), Node(3, Leaf, Leaf))
    println(sum(t))
  }
}

なぜADTなのか

ADTが強力なのは、次のことができるためです。

  • データをsum型とproduct型として正確に表現できます
  • 不正な状態を構築できなくできます
  • 網羅的なパターンマッチングと完全に組み合わせられます
  • 木やリストのような再帰的構造にも対応できます

ADTと継承の比較

従来のOOPでは、サブクラスごとに振る舞いが分散します。ADTではデータ定義を閉じた状態に保ち、パターンマッチングを行う関数に振る舞いを置きます。

このデータと振る舞いの分離は、関数型設計の特徴です。

すべてを組み合わせる

すべてのバリアントを処理する関数を備えた、完全な小規模ADTです。

sealed trait Json
case class JNum(n: Double) extends Json
case class JStr(s: String) extends Json
case object JNull extends Json
object Main {
  def render(j: Json): String = j match {
    case JNum(n) => n.toString
    case JStr(s) => "\"" + s + "\""
    case JNull   => "null"
  }
  def main(args: Array[String]): Unit = {
    List(JNum(3.0), JStr("hi"), JNull).foreach(j => println(render(j)))
  }
}

クイックチェック

ADTについての理解度を確認しましょう。

まとめ

代数的データ型の構築方法を学びました。

  • sum型:複数のバリアントを持つsealed trait(OR)
  • product型:フィールドを持つcase class(AND)
  • これらを組み合わせてドメインを正確にモデル化します
  • ADTは再帰的にできます(木、リスト)
  • パターンマッチングで処理します

よくある質問

「代数的データ型」レッスンは無料ですか?

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

「代数的データ型」で何を学びますか?

ドメインをモデル化します。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

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

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

「代数的データ型」レッスンにはどのくらい時間がかかりますか?

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

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

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

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

  1. ケースクラス
  2. Sealed トレイト
  3. 代数的データ型
  4. 網羅的マッチング
← Scala for Backend Engineering & Functional Programmingに戻る