SlideShare a Scribd company logo
1 of 83
Download to read offline
Essential Scala 第4章
トレイトによるデータモデリング
2018.8.1
Takuya Tsuchida (@takuya0301)
第4章 トレイトによるデータモデリング
4.1 トレイト
4.2 あれかこれかで他にはない:シールドトレイト
4.3 トレイトによるデータモデリング
4.4 直和型パターン
4.5 データで作業する
4.6 再帰的データ
4.7 大きな例
4.8 まとめ
2
第4章 トレイトによるデータモデリング
前章でクラスの奥深さを見ました。クラスは類似した属性を持つオブジェクトを抽象化す
る方法を提供し、クラスに属するどんなオブジェクトでも動作するコードを書けるようにな
りました。
本章ではクラスを抽象化する方法を探検し、異なるクラスのオブジェクトでも動作する
コードを書きます。これをトレイトと呼ばれるメカニズムで実現します。
本章は視点の変更を示します。前章では Scala コードを構成する技術的側面を重視し
てきました。本章のはじめでもトレイトの技術的側面を重視します。その視点は、思考を
表現する媒体として Scala を使用することに変化していきます。
代数的データ型と呼ばれるデータの記述をコードに機械的に変換する方法を見ていきま
す。構造的再帰を使用することで、代数的データ型を変換するコードを機械的に記述で
きます。 3
4.1 トレイト
トレイトはクラス作成のためのテンプレートで、クラスがオブジェクト作成のテンプレートで
あるのと同様です。トレイトは2つ以上のクラスを同じと見なす表現で、いずれも同じ操作
を実装します。言い換えると、トレイトは共通の基底型を共有する複数のクラスを表現し
ます。
4
ノート:トレイト対 Java インターフェイス
トレイトはデフォルトメソッドを伴う Java 8 のインターフェイスにとても似ている。Java 8
を使用したことがないのであれば、インターフェイスと抽象クラスを掛け合わせたものが
トレイトであると考えていい。
5
4.1.1 トレイトの例
トレイトの例からはじめます。Web サイトの訪問者をモデリングすることを想像します。
訪問者には2つの型、サイトに登録済みと匿名があります。
case class Anonymous(
id: String,
createdAt: Date = new Date()
)
case class User(
id: String,
email: String,
createdAt: Date = new Date()
)
4.1.1 トレイトの例
そこには明白な重複がありますが、同じ定義を2回書かない方がいいでしょう。より重要
ことは、2種類の訪問者に共通する型をつくることです。共通の型を持たせることができ
れば、どの種類の訪問者でも動作するメソッドを書くことができます。これをトレイトで実
現します。
trait Visitor {
def id: String // 各ユーザーに付与されるユニークな ID
def createdAt: Date // このユーザーがサイトにはじめて訪れた日付
// 訪問者がどのくらいの時間そこにいたか?
def age: Long = new Date().getTime - createdAt.getTime
}
4.1.1 トレイトの例
case class Anonymous(
id: String,
createdAt: Date = new Date()
) extends Visitor
case class User(
id: String,
email: String,
createdAt: Date = new Date()
) extends Visitor
4.1.1 トレイトの例
下記の2つについて変更しています。
● Visitor トレイトを定義する
● extends キーワードを使用し Visitor トレイトの派生型として Anonymous と User
を宣言する
Visitor トレイトは、どんな派生型でも必ず実装しなければならないインターフェイスを表
現します。派生型は id と呼ばれる文字列と日付の createdAt を必ず実装します。また、
どんな Visitor の派生型でも Visitor に定義されている age メソッドを自動的に持ちま
す。
4.1.1 トレイトの例
Visitor トレイトを定義することによって、どんな訪問者の派生型についても動作するメ
ソッドを書くことができます。
def older(v1: Visitor, v2: Visitor): Boolean =
v1.createdAt.before(v2.createdAt)
older(Anonymous("1"), User("2", "test@example.com"))
// res4: Boolean = true
older メソッドは Visitor の派生型である Anonymous でも User でも呼び出すことがで
きます。
ノート:トレイト文法
トレイトは下記のように宣言できる。
trait TraitName {
declarationOrExpression ...
}
トレイトの派生型であるクラスやケースクラスは下記のように宣言できる。
class Name(...) extends TraitName {
...
}
case class Name(...) extends TraitName {
...
} 14
4.1.2 トレイトとクラスの比較
クラスのように、トレイトはフィールド定義とメソッド定義の名付けられた集合です。しか
し、下記の点でクラスとは違います。
トレイトはコンストラクターを持てません。トレイトからは直接オブジェクトを生成できませ
ん。その代わりにクラスを生成するためにトレイトを使用し、そのクラスからオブジェクト
を生成します。
トレイトは名前と型を持ち実装を持たない抽象メソッドを定義できます。これを Visitor ト
レイトで見ました。トレイトを拡張したクラスを生成するときには実装を指定する必要があ
りますが、それまでは定義を抽象なままにしておいてかまいません。
4.1.2 トレイトとクラスの比較
抽象的な定義を探すために Visitor トレイトに立ち返ってみましょう。
trait Visitor {
def id: String // 各ユーザーに付与されるユニークな ID
def createdAt: Date // このユーザーがサイトにはじめて訪れた日付
// 訪問者がどのくらいの時間そこにいたか?
def age: Long = new Date().getTime - createdAt.getTime
}
Visitor は2つの抽象メソッドを規定しています。メソッドは実装を持ちませんが、派生クラ
スで実装されなければなりません。その対象として id と createdAt があります。また、ひ
とつの抽象メソッドを項として定義に含む、具象メソッドである age を定義しています。
4.1.2 トレイトとクラスの比較
Visitor は Anonymous と User という2つのクラスのためのビルディングブロックとして
使用されています。各クラスは Visitor を拡張しており、それはそのフィールドとメソッド
のすべてを継承していることを意味します。
Anonymous("anon1")
// res14: Anonymous = Anonymous(anon1)
res14.createdAt
// res15: java.util.Date = Mon Mar 24 15:11:45 GMT 2014
res14.age
// res16: Long = 8871
4.1.2 トレイトとクラスの比較
id と createdAt は抽象なので、それらは派生クラスで定義される必要があります。例の
クラスでは def ではなく val として実装しています。Scala ではこれが認められており、
val を一般化したものが def であると見なされます * 。トレイトの中で val を定義せずに
def を使用することはいいことです。具体的な実装は適切に def か val を使用して実装
しましょう。
* オブジェクトリテラルについての課題で見た統一形式アクセスの原則のことです。
4.1.3 キーポイント:トレイト
トレイトは、オブジェクトを抽象化する方法としてのクラスのように、類似した属性を持つ
クラスを抽象化する方法です。
トレイトと、トレイトを継承したクラス(普通はケースクラス)を宣言することで使用します。
trait TraitName {
declarationOrExpression ...
}
case class Name(...) extends TraitName {
...
}
4.2 あれかこれかで他にはない:シールドトレイト
多くの場合に、トレイトを拡張することが考えうるすべてのクラスを列挙できます。例え
ば、Web サイトの訪問者を Anonymous かログイン済みの User としてモデリングしま
した。それら2つのケースは可能なもののすべてを含むので、一方のケースの反対は他
方のケースになります。これはシールドトレイトでモデリングでき、コンパイラーが追加の
検査を提供してくれます。
4.2 あれかこれかで他にはない:シールドトレイト
シールドトレイトはトレイト宣言に sealed と記述するだけで作成できます。
sealed trait Visitor {
def id: String
def createdAt: Date
def age: Long = new Date().getTime() - createdAt.getTime()
}
case class User(id: String, email: String,
createdAt: Date = new Date()) extends Visitor
case class Anonymous(id: String,
createdAt: Date = new Date()) extends Visitor
4.2 あれかこれかで他にはない:シールドトレイト
シールドとしてトレイトをマークしたときは、同じファイルですべての派生型を定義しなけ
ればなりません。ひとたびトレイトがシールドになると、コンパイラーは派生型の完全な
集合を把握し、パターンマッチ式で不足しているケースがあると警告してくれます。
def missingCase(v: Visitor) = v match {
case User(_, _, _) => "Got a user"
}
// <console>:15: warning: match may not be exhaustive.
// It would fail on the following input: Anonymous(_, _)
// def missingCase(v: Visitor) = v match {
// ^
// missingCase: (v: Visitor)String
4.2 あれかこれかで他にはない:シールドトレイト
シールドトレイトの派生型は、それが定義されているファイル外で拡張できてしまいま
す。派生型をファイル内での拡張が可能な sealed か final として宣言することで防ぐこ
とができます。
sealed trait Visitor { /* ... */ }
final case class User(/* ... */) extends Visitor
final case class Anonymous(/* ... */) extends Visitor
ノート:シールドトレイト文法
トレイトにおけるすべての派生型が既知であればトレイトを封印すべきである。
sealed trait TraitName {
...
}
派生型を拡張することがなければ、派生型を final にすることを検討すべきである。
final case class Name(...) extends TraitName {
...
}
なお、派生型はシールドトレイトと同じファイルで定義されなければならない。
26
4.2.1 キーポイント:シールドトレイト
シールドトレイトとファイナル(ケース)クラスは型の拡張性を制御できるようにします。大
多数はシールドトレイトとファイナルケースクラスのパターンとして使用されます。
sealed trait TraitName { ... }
final case class Name(...) extends TraitName
このパターンの主な利点は、コンパイラーがパターンマッチで不足している型を警告して
くれることと、シールドトレイトを拡張する場所を制御することで派生型の振る舞いを保証
できることです。
4.3 トレイトによるデータモデリング
本節では言語機能からプログラミングパターンに焦点を移していきます。データモデリン
グについて見ていきながら、論理和と論理積の見地から様々なデータモデルをScala で
表現するプロセスを学びます。オブジェクト指向プログラミングの専門用語である is-a 関
係と has-a 関係を表現し、関数プログラミングの専門用語である、代数的データ型と呼
ばれる直和型と直積型を学びます。
本節でのゴールは、どうデータモデルを Scala コードに変換するかを見るということで
す。次節では代数的データ型を使用したコードのパターンを見ます。
4.3.1 直積型パターン
最初のパターンは、他のデータを含むデータをモデリングするものです。「A は B と C を
持つ」と説明できます。
これはケースクラスを使用して記述します。
ノート:直積型パターン
A が B 型の b と C 型の c を持つ場合、このように記述する。
case class A(b: B, c: C)
or
trait A {
def b: B
def c: C
}
30
4.4 直和型パターン *
次のパターンは、2つ以上の異なったケースになるデータをモデリングするものです。「A
は B か C である」と説明できます。
これはシールドトレイトとケースクラスのパターンで記述します。
* 訳注:節番号が 4.3.2 になる内容です。おそらく誤植と考えられます。
ノート:直和型パターン
A が B か C である場合、このように記述する。
sealed trait A
final case class B() extends A
final case class C() extends A
32
4.4.1 代数的データ型
代数的データ型は、前述の2つのパターンを使用したデータになります。関数プログラミ
ングの文脈では、has-a and パターンは直積型であり、is-a or パターンは直和型です。
4.4.2 不足しているパターン
is-a / has-a と and / or という2軸の関係性を見てきました。この定義を表にすると4つの
セルについて2つのパターンしか見ていません。
2つの不足しているパターンは何でしょうか?
And Or
Is-a 直和型
Has-a 直積型
4.4.2 不足しているパターン
is-a and パターンは「A は B かつ C である」を意味します。このパターンはある点にお
いて直和型の逆になり、下記のように実装できます。
trait B
trait C
trait A extends B with C
4.4.2 不足しているパターン
トレイトはたくさんのトレイトから拡張することができます。しかし、本稿ではこのパターン
を使用しません。異なるインターフェイスで構成されるデータを表現する場合、あとから
学習する型クラスを使用します。
道理に合っている場合には、is-a and パターンを使用することもあります。
● モジュール性のためにケークパターン * を使用する場合
● いくつかのクラスを横断して実装を共有するときに、メイントレイトがデフォルト実装
を持つことが妥当でない場合
* http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/
4.4.2 不足しているパターン
has-a or パターンは「A は B か C を持つ」を意味します。これを実装するには2つの方
法があります。
「A は D を持ち、D は B か C である」と言えます。これを実装するために2つのパターン
を機械的に適用することができます。
trait A {
def d: D
}
sealed trait D
final case class B() extends D
final case class C() extends D
4.4.2 不足しているパターン
あるいは、「A は D か E である、D は B を持ち、E は C を持つ」と言えます。これも直
接的にコードに変換できます。
sealed trait A
final case class D(b: B) extends A
final case class E(c: C) extends A
4.4.3 キーポイント:トレイトによるデータモデリング
直積型による has-a and パターンと直和型による is-a or パターンで、データを機械的
に Scala コードを変換するのを見ました。このタイプのデータは代数的データ型として知
られています。それらのパターンを理解することは理想的な Scala コードを書く上でとて
も重要です。
4.5 データで作業する
本節では代数的データ型を使用したパターン、構造的再帰を見ていきます。
構造的再帰は代数的データ型を組み立てるプロセスのちょうど反対です。直和型パター
ンと直積型パターンは、組み合わせて大きなデータをつくる方法を教えてくれます。構造
的再帰は本質的には小さな部品に分割するプロセスです。
代数的データ型を構築するためにちょうど2つのパターンがありましたが、構造的再帰を
用いて分解するためにも2つのパターンがあります。実際にはそれぞれのパターンにつ
いて2つの変種があり、ひとつは典型的なオブジェクト指向スタイルでポリモーフィズムを
使用したもので、もうひとつは典型的な関数スタイルでパターンマッチを使用したもので
す。どちらの使用を選択すべきかのいくつかのルールで本節を締め括ります。
4.5.1 ポリモーフィズムを使用した構造的再帰
多相ディスパッチもしくはポリモーフィズムはオブジェクト指向技術の基礎をなします。ト
レイトでメソッドを定義し、トレイトを拡張したクラスで異なる実装を持つ場合、具象インス
タンスで実装されたメソッドが呼び出されます。
4.5.1 ポリモーフィズムを使用した構造的再帰
直和型を使用したシンプルな定義から始めます。
sealed trait A {
def foo: String
}
final case class B() extends A {
def foo: String = "It's B!"
}
final case class C() extends A {
def foo: String = "It's C!"
}
4.5.1 ポリモーフィズムを使用した構造的再帰
val anA: A = B()
// anA: A = B()
anA.foo
// res1: String = It's B!
val anA: A = C()
// anA: A = C()
anA.foo
// res2: String = It's C!
4.5.1 ポリモーフィズムを使用した構造的再帰
トレイトで実装を定義することもでき、派生クラスでは override キーワードを使用して実
装を変更します。
sealed trait A {
def foo: String = "It's A!"
}
final case class B() extends A {
override def foo: String = "It's B!"
}
final case class C() extends A {
override def foo: String = "It's C!"
}
4.5.1 ポリモーフィズムを使用した構造的再帰
val anA: A = B()
// anA: A = B()
anA.foo
// res1: String = It's B!
トレイトでデフォルト実装を提供する場合、すべての派生型で妥当な実装であることを確
実にすべきということを覚えておいてください。
ノート:直積型ポリモーフィズムパターン
A が B 型の b と C 型の c を持ち、F 型を返すメソッド f を記述したい場合、シンプルに
いつもの方法でメソッドを記述する。
case class A(b: B, c: C) {
def f: F = ???
}
メソッドの本体で、F 型の結果を構築するために、 b と c とメソッド引数を必ず使用しな
ければならない。
48
ノート:直和型ポリモーフィズムパターン
A が B か C であり、F 型を返すメソッド f を記述したい場合、A で f を抽象メソッドとして
定義し、B と C で具象実装を提供する。
sealed trait A {
def f: F
}
final case class B() extends A {
def f: F = ???
}
final case class C() extends A {
def f: F = ???
}
49
4.5.2 パターンマッチを使用した構造的再帰
パターンマッチによる構造的再帰はポリモーフィズムと同じ線に沿って進みます。それぞ
れの派生型についてのケースをシンプルに持ち、パターンマッチにおける各ケースにお
いて興味のあるフィールドを抽出できます。
ノート:直積型パターンマッチパターン
A が B 型の b と C 型の c を持ち、A を受け入れ F を返すメソッド f を記述したい場合、
下記のように記述する。
def f(a: A): F = a match {
case A(b, c) => ???
}
メソッドの本体で、F 型の結果を構築するために、 b と c を使用する。
51
ノート:直和型パターンマッチパターン
A が B か C であり、A を受け入れ F を返すメソッド f を記述したい場合、B と C をパ
ターンマッチのケースとして定義する。
def f(a: A): F = a match {
case B() => ???
case C() => ???
}
52
4.5.3 完全な例:共通
sealed trait Food
final case object Antelope extends Food
final case object TigerFood extends Food
final case object Licorice extends Food
final case class CatFood(food: String) extends Food
4.5.3 完全な例:ポリモーフィズム
sealed trait Feline {
def dinner: Food
}
final case class Lion() extends Feline {
def dinner: Food = Antelope
}
final case class Tiger() extends Feline {
def dinner: Food = TigerFood
}
final case class Panther() extends Feline {
def dinner: Food = Licorice
}
final case class Cat(favouriteFood: String) extends Feline {
def dinner: Food = CatFood(favouriteFood)
}
4.5.3 完全な例:パターンマッチ(基底トレイト)
sealed trait Feline {
def dinner: Food = this match {
case Lion() => Antelope
case Tiger() => TigerFood
case Panther() => Licorice
case Cat(favouriteFood) => CatFood(favouriteFood)
}
}
final case class Lion() extends Feline
final case class Tiger() extends Feline
final case class Panther() extends Feline
final case class Cat(favouriteFood: String) extends Feline
4.5.3 完全な例:パターンマッチ(別オブジェクト)
sealed trait Feline
final case class Lion() extends Feline
final case class Tiger() extends Feline
final case class Panther() extends Feline
final case class Cat(favouriteFood: String) extends Feline
object Diner {
def dinner(feline: Feline): Food = feline match {
case Lion() => Antelope
case Tiger() => TigerFood
case Panther() => Licorice
case Cat(food) => CatFood(food)
}
}
4.5.4 使用するパターンの選び方
構造的再帰を実装するのに3つの方法があります。
1. ポリモーフィズム
2. 基底トレイトでのパターンマッチ
3. 外部オブジェクトでのパターンマッチ
使用するパターンは下記のルールを参考に選んでみてください。
● 実装がクラス内のフィールドやメソッドだけに依存している
→ 1 or 2(一般的に重複するコードが少ない2が選ばれる)
● 実装がクラス外のデータに依存している → 3
● 複数の実装が必要になる → 3
4.5.5 「オブジェクト指向」対「関数的拡張性」
典型的な関数プログラミングスタイルはパターンマッチを使用し、典型的なオブジェクト
指向スタイルはポリモーフィズムを使用します。関数プログラミングスタイルの利点はコ
ンパイラーがより手助けしてくれることです。
オブジェクト指向スタイルは、トレイトを拡張することで新しいデータを容易に追加できま
すが、新しいメソッドを追加するためには既存のコードを変更しなければなりません。関
数プログラミングスタイルは、新しいメソッドを容易に追加できますが、新しいデータを追
加するためには既存のコードを変更しなければなりません。
新しいメソッドを追加する 新しいデータを追加する
オブジェクト指向 既存のコードを変更する 既存のコードを変更しない
関数プログラミング 既存のコードを変更しない 既存のコードを変更する
4.5.5 「オブジェクト指向」対「関数的拡張性」
Scala はポリモーフィズムとパターンマッチの両方を使用できる柔軟性を持つので、どち
らも適切に使用すべきです。しかしながら、コードの意味論について優れた保証を与え
るシールドトレイトを一般的に好み、後述する型クラスを使用することでオブジェクト指向
スタイルの拡張性を手に入れることができます。
4.6 再帰的データ
とくに代数的データ型は再帰的データの定義によく使用されます。このデータはそれ自
身の項によって定義され、サイズを制約しないデータを作成します。
ただし、再帰が永遠に続くため、このようには定義できません。
final case class Broken(broken: Broken)
最後を表すベースケースを定義することで妥当な再帰的データを定義できます。
sealed trait IntList
final case object End extends IntList
final case class Pair(head: Int, tail: IntList) extends IntList
Pair(1, Pair(2, Pair(3, End)))
// res: Pair = Pair(1,Pair(2,Pair(3,End)))
4.6 再帰的データ
再帰的代数的データ型を処理するために構造的再帰パターンを適用できます。
それでは IntList のすべての要素を加算してみましょう。まずは、メソッド定義とテストを
記述するところから始めます。
def sum(list: IntList): Int = ???
val example = Pair(1, Pair(2, Pair(3, End)))
assert(sum(example) == 6)
assert(sum(example.tail) == 5)
assert(sum(End) == 0)
4.6 再帰的データ
メソッドの本体に構造的再帰パターンを適用してみましょう。
def sum(list: IntList): Int = list match {
case End => ???
case Pair(hd, tl) => ???
}
4.6 再帰的データ
End の解答は 0 と決定できます。Pair は Int 型を返す必要があり、tl について再帰呼
び出しをする必要があります。
def sum(list: IntList): Int = list match {
case End => 0
case Pair(hd, tl) => ??? sum(tl)
}
4.6 再帰的データ
再帰呼び出しは残りのリストの合計返すので、その結果に hd を加算します。
def sum(list: IntList): Int = list match {
case End => 0
case Pair(hd, tl) => hd + sum(tl)
}
4.6.1 ベースケースと再帰ケースを理解する
ベースケースと再帰ケースの本体を与える上で、一般的な指針があります。
ベースケースは、一般的にその計算における単位元を返します。例えば、加算の単位
元は0で、乗算の単位元は1です。
再帰ケースは、正しい結果を返す再帰と仮定し、正しい解答が得られるように実装を追
加しました。sum で見たように、再帰呼び出しが残りのリストについて正しい結果を与え
ることを仮定し、リストの先頭をただ追加しました。
ノート:再帰的代数的データ型パターン
再帰的代数的データ型を定義するとき、ひとつは再帰的で、もうひとつは再帰的ではな
い、という2つのケースが少なくとも必要である。ベースケースとして知られるものは再帰
的ではない。コードでの一般的なスケルトンは下記のとおりである。
sealed trait RecursiveExample
final case class RecursiveCase(recursion: RecursiveExample)
extends RecursiveExample
final case object BaseCase extends RecursiveExample
74
ノート:再帰的構造的再帰パターン
再帰的代数的データ型で構造的再帰コードを記述するときは下記のような対応をする。
● データにおいて再帰要素に遭遇するときはいつも、メソッドの再帰的呼び出しを行う
● データにおいてベースケースに遭遇するときはいつも、実行しようとしている計算の
単位元を返す
76
4.6.2 末尾再帰
再帰によって大量のスタック領域を消費してしまうのではないかと心配するかもしれませ
ん。Scala は末尾再帰と呼ばれる最適化を適用するため、多くの再帰関数はスタック領
域を消費し続けることはありません。
末尾呼び出しは、メソッドを呼び出した値をただちに返すメソッド呼び出しです。下記の
tailCall は、method1 の結果をただちに返すので末尾呼び出しです。
def method1: Int = 1
def tailCall: Int = method1
下記の notTailCall は、数値を加算をしているため、 method1 の結果をただちに返さな
いので末尾呼び出しではありません。
def notATailCall: Int = method1 + 2
4.6.2 末尾再帰
末尾呼び出しはスタック領域を使用しないよう最適化できます。JVM の制約から Scala
は自分自身を呼び出す末尾呼び出ししか最適化できません。よって末尾再帰は保守面
で重要で、@tailrec アノテーションを使用することでコンパイラーに末尾再帰になってい
るかをチェックさせることができます。
4.6.2 末尾再帰
import scala.annotation.tailrec
@tailrec
def sum(list: IntList): Int = list match {
case End => 0
case Pair(hd, tl) => hd + sum(tl)
}
// <console>:18: error: could not optimize @tailrec annotated method sum: it
...
// def sum(list: IntList): Int = list match {
// ^
@tailrec
def sum(list: IntList, total: Int = 0): Int = list match {
case End => total
case Pair(hd, tl) => sum(tl, total + hd)
}
// sum: (list: IntList, total: Int)Int
4.6.2 末尾再帰
どんな非末尾再帰関数でも、前述の sum で実現したようにアキュムレーターを追加す
ることで末尾再帰版に変換することができます。
Scala で末尾再帰関数を直接書いて処理することはあまりなく、Scala の充実したコレク
ションライブラリを使用することで末尾再帰で実現したいことのほとんどを実現できます。
4.7 大きな例 *
大きなプロジェクトの例です。
1. Calculator
2. JSON
3. Music
* 訳注:課題の節なので説明は割愛します。
4.8 まとめ
本章では重要な視点の変更を行い、言語機能から離れ、言語機能がサポートするプロ
グラミングパターンに目を向けました。これは本稿の残りでも継続します。
2つの重要なパターン、代数的データ型と構造的再帰を探究しました。それらのパターン
は、データのメンタルモデルから、まったく機械的な方法による Scala におけるデータの
表現と処理に我々を向かわせます。月並みなコードの構造や理解を容易にするだけで
はなく、コンパイラーが開発や保守を容易にするために共通のエラーを捕捉してくれま
す。これら2つのツールは、慣用的な関数的コードで一般に使用され、その重要性はど
れほど強調してもしすぎることはありません。
本章における課題の中で共通のデータ構造を開発しましたが、固定された型のデータし
か保持できなく、そのコードは多くの繰り返しが含まれていました。次章では、型とメソッ
ドを超えた抽象化を見ていきながら、シーケンス処理におけるいくつかの重要なコンセプ
トを紹介します。

More Related Content

What's hot

DLL_言語系MicrosoftAIサービス最新情報_202302.pdf
DLL_言語系MicrosoftAIサービス最新情報_202302.pdfDLL_言語系MicrosoftAIサービス最新情報_202302.pdf
DLL_言語系MicrosoftAIサービス最新情報_202302.pdfAyako Omori
 
実践的な設計って、なんだろう?
実践的な設計って、なんだろう?実践的な設計って、なんだろう?
実践的な設計って、なんだろう?増田 亨
 
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」までNeo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」までKeiichiro Seida
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し増田 亨
 
Apache Arrow - データ処理ツールの次世代プラットフォーム
Apache Arrow - データ処理ツールの次世代プラットフォームApache Arrow - データ処理ツールの次世代プラットフォーム
Apache Arrow - データ処理ツールの次世代プラットフォームKouhei Sutou
 
Writing Spring WebFlux more esay with kotlin
Writing Spring WebFlux more esay with kotlinWriting Spring WebFlux more esay with kotlin
Writing Spring WebFlux more esay with kotlin賢太郎 前多
 
Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Takayuki Shimizukawa
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxShota Shinogi
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ増田 亨
 
Laravelを用いたゲームサーバーのチューニング
Laravelを用いたゲームサーバーのチューニングLaravelを用いたゲームサーバーのチューニング
Laravelを用いたゲームサーバーのチューニングNOW PRODUCTION
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかShohei Okada
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意Yoshitaka Kawashima
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪Takuto Wada
 
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Ryosuke Uchitate
 
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)Mikiya Okuno
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門Takuya Kitamura
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話Koichiro Matsuoka
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法についてYuji Otani
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?Moriharu Ohzu
 

What's hot (20)

DLL_言語系MicrosoftAIサービス最新情報_202302.pdf
DLL_言語系MicrosoftAIサービス最新情報_202302.pdfDLL_言語系MicrosoftAIサービス最新情報_202302.pdf
DLL_言語系MicrosoftAIサービス最新情報_202302.pdf
 
実践的な設計って、なんだろう?
実践的な設計って、なんだろう?実践的な設計って、なんだろう?
実践的な設計って、なんだろう?
 
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」までNeo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
Neo4j の「データ操作プログラミング」から 「ビジュアライズ」まで
 
リッチなドメインモデル 名前探し
リッチなドメインモデル 名前探しリッチなドメインモデル 名前探し
リッチなドメインモデル 名前探し
 
Apache Arrow - データ処理ツールの次世代プラットフォーム
Apache Arrow - データ処理ツールの次世代プラットフォームApache Arrow - データ処理ツールの次世代プラットフォーム
Apache Arrow - データ処理ツールの次世代プラットフォーム
 
Writing Spring WebFlux more esay with kotlin
Writing Spring WebFlux more esay with kotlinWriting Spring WebFlux more esay with kotlin
Writing Spring WebFlux more esay with kotlin
 
Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?Pythonはどうやってlen関数で長さを手にいれているの?
Pythonはどうやってlen関数で長さを手にいれているの?
 
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptxネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
ネットストーカー御用達OSINTツールBlackBirdを触ってみた.pptx
 
オブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツオブジェクト指向の設計と実装の学び方のコツ
オブジェクト指向の設計と実装の学び方のコツ
 
Laravelを用いたゲームサーバーのチューニング
Laravelを用いたゲームサーバーのチューニングLaravelを用いたゲームサーバーのチューニング
Laravelを用いたゲームサーバーのチューニング
 
Laravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのかLaravel の paginate は一体何をやっているのか
Laravel の paginate は一体何をやっているのか
 
イミュータブルデータモデルの極意
イミュータブルデータモデルの極意イミュータブルデータモデルの極意
イミュータブルデータモデルの極意
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!Amazon Cognito使って認証したい?それならSpring Security使いましょう!
Amazon Cognito使って認証したい?それならSpring Security使いましょう!
 
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
なぜ、いま リレーショナルモデルなのか(理論から学ぶデータベース実践入門読書会スペシャル)
 
ドメイン駆動設計入門
ドメイン駆動設計入門ドメイン駆動設計入門
ドメイン駆動設計入門
 
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話DDD x CQRS   更新系と参照系で異なるORMを併用して上手くいった話
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
 
Redisの特徴と活用方法について
Redisの特徴と活用方法についてRedisの特徴と活用方法について
Redisの特徴と活用方法について
 
Azure IoT/AI最前線
Azure IoT/AI最前線Azure IoT/AI最前線
Azure IoT/AI最前線
 
オブジェクト指向できていますか?
オブジェクト指向できていますか?オブジェクト指向できていますか?
オブジェクト指向できていますか?
 

Similar to Essential Scala 第4章 トレイトによるデータモデリング

Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス Takuya Tsuchida
 
Essential Scala 第5章 シーケンス処理
Essential Scala 第5章 シーケンス処理Essential Scala 第5章 シーケンス処理
Essential Scala 第5章 シーケンス処理Takuya Tsuchida
 
ゆるふわScalaコップ本読書会 第7章
ゆるふわScalaコップ本読書会 第7章ゆるふわScalaコップ本読書会 第7章
ゆるふわScalaコップ本読書会 第7章Yuta Yokoi
 
Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値Takuya Tsuchida
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行guest5f4320
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜Hiromi Ishii
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
C# 7・8 の復習
C# 7・8 の復習C# 7・8 の復習
C# 7・8 の復習m ishizaki
 
TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語gypsygypsy
 

Similar to Essential Scala 第4章 トレイトによるデータモデリング (13)

Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス Essential Scala 第3章 オブジェクトとクラス
Essential Scala 第3章 オブジェクトとクラス
 
Essential Scala 第5章 シーケンス処理
Essential Scala 第5章 シーケンス処理Essential Scala 第5章 シーケンス処理
Essential Scala 第5章 シーケンス処理
 
ゆるふわScalaコップ本読書会 第7章
ゆるふわScalaコップ本読書会 第7章ゆるふわScalaコップ本読書会 第7章
ゆるふわScalaコップ本読書会 第7章
 
Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値Essential Scala 第2章 式、型、値
Essential Scala 第2章 式、型、値
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
 
Phantom Type in Scala
Phantom Type in ScalaPhantom Type in Scala
Phantom Type in Scala
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
C# 7・8 の復習
C# 7・8 の復習C# 7・8 の復習
C# 7・8 の復習
 
TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語TypeScript & 関数型講座 第2回 TypeScript という言語
TypeScript & 関数型講座 第2回 TypeScript という言語
 

More from Takuya Tsuchida

Mikatus エンジニアの成長戦略
Mikatus エンジニアの成長戦略Mikatus エンジニアの成長戦略
Mikatus エンジニアの成長戦略Takuya Tsuchida
 
コンポーネントアプローチによるソフトウェア開発の俊敏性と品質向上の実現~カスタマーショーケース
コンポーネントアプローチによるソフトウェア開発の俊敏性と品質向上の実現~カスタマーショーケースコンポーネントアプローチによるソフトウェア開発の俊敏性と品質向上の実現~カスタマーショーケース
コンポーネントアプローチによるソフトウェア開発の俊敏性と品質向上の実現~カスタマーショーケースTakuya Tsuchida
 
帳票も今や HTML でつくる時代!?日本の税理士を支えるサーバーレス帳票基盤
帳票も今や HTML でつくる時代!?日本の税理士を支えるサーバーレス帳票基盤帳票も今や HTML でつくる時代!?日本の税理士を支えるサーバーレス帳票基盤
帳票も今や HTML でつくる時代!?日本の税理士を支えるサーバーレス帳票基盤Takuya Tsuchida
 
youtube-dl に Pull Request 送ったった
youtube-dl に Pull Request 送ったったyoutube-dl に Pull Request 送ったった
youtube-dl に Pull Request 送ったったTakuya Tsuchida
 
Waze Map Editor クイックスタートガイド
Waze Map Editor クイックスタートガイドWaze Map Editor クイックスタートガイド
Waze Map Editor クイックスタートガイドTakuya Tsuchida
 
Google App Engine for Java
Google App Engine for JavaGoogle App Engine for Java
Google App Engine for JavaTakuya Tsuchida
 

More from Takuya Tsuchida (6)

Mikatus エンジニアの成長戦略
Mikatus エンジニアの成長戦略Mikatus エンジニアの成長戦略
Mikatus エンジニアの成長戦略
 
コンポーネントアプローチによるソフトウェア開発の俊敏性と品質向上の実現~カスタマーショーケース
コンポーネントアプローチによるソフトウェア開発の俊敏性と品質向上の実現~カスタマーショーケースコンポーネントアプローチによるソフトウェア開発の俊敏性と品質向上の実現~カスタマーショーケース
コンポーネントアプローチによるソフトウェア開発の俊敏性と品質向上の実現~カスタマーショーケース
 
帳票も今や HTML でつくる時代!?日本の税理士を支えるサーバーレス帳票基盤
帳票も今や HTML でつくる時代!?日本の税理士を支えるサーバーレス帳票基盤帳票も今や HTML でつくる時代!?日本の税理士を支えるサーバーレス帳票基盤
帳票も今や HTML でつくる時代!?日本の税理士を支えるサーバーレス帳票基盤
 
youtube-dl に Pull Request 送ったった
youtube-dl に Pull Request 送ったったyoutube-dl に Pull Request 送ったった
youtube-dl に Pull Request 送ったった
 
Waze Map Editor クイックスタートガイド
Waze Map Editor クイックスタートガイドWaze Map Editor クイックスタートガイド
Waze Map Editor クイックスタートガイド
 
Google App Engine for Java
Google App Engine for JavaGoogle App Engine for Java
Google App Engine for Java
 

Recently uploaded

新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NTT DATA Technology & Innovation
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルCRI Japan, Inc.
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)Hiroshi Tomioka
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。iPride Co., Ltd.
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイスCRI Japan, Inc.
 

Recently uploaded (7)

新人研修 後半 2024/04/26の勉強会で発表されたものです。
新人研修 後半        2024/04/26の勉強会で発表されたものです。新人研修 後半        2024/04/26の勉強会で発表されたものです。
新人研修 後半 2024/04/26の勉強会で発表されたものです。
 
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
NewSQLの可用性構成パターン(OCHaCafe Season 8 #4 発表資料)
 
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その22024/04/26の勉強会で発表されたものです。
 
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアルLoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
LoRaWAN スマート距離検出デバイスDS20L日本語マニュアル
 
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
業務で生成AIを活用したい人のための生成AI入門講座(社外公開版:キンドリルジャパン社内勉強会:2024年4月発表)
 
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
Amazon SES を勉強してみる その32024/04/26の勉強会で発表されたものです。
 
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
LoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイスLoRaWANスマート距離検出センサー  DS20L  カタログ  LiDARデバイス
LoRaWANスマート距離検出センサー DS20L カタログ LiDARデバイス
 

Essential Scala 第4章 トレイトによるデータモデリング