カスタム型を使うと、Gleamで新しいデータ型を定義できます。カスタム型には複数の_バリアント_を持たせることができ、それぞれに名前を付けられます。
pub type Season {
Spring
Summer
Autumn
Winter
}
カスタム型の各ケースには、必要に応じてデータを持たせることができ、ケースごとに持てるデータの型も変えられます。データを持つバリアントのことを_レコード_と呼びます。
pub type Number {
SomeInt(Int)
SomeFloat(Float)
Invalid
}
特定のケースの値を作るには、追加のデータを持たない場合はその名前をそのまま使います(Spring)。データを持つ場合は、関数のように呼び出します(SomeInt(2))。
let spring = Spring
let integerTwo = SomeInt(2)
カスタム型は、Gleamのあらゆる値と同じく、_構造的等価性_を持ちます。これは、同じバリアントで同じデータを持つ2つの値は等しいとみなされるという意味です。
Spring == Spring // -> True
Spring == Autumn // -> False
SomeInt(2) == SomeInt(2) // -> True
SomeInt(2) == SomeFloat(2.0) // -> False
カスタム型のバリアントは、case式を使ってパターンマッチできます。
import gleam/int
import gleam/float
pub fn describe(flexible_number: Number) -> String {
case flexible_number {
SomeFloat(f) -> "Float: " <> float.to_string(f)
SomeInt(i) -> "Int: " <> int.to_string(i)
Invalid -> "Neither a float nor an int"
}
}
この演習の舞台はバレンタインデーです。パートナーと一緒に何か楽しいことをしようと計画しています。パートナーはたくさんのアイデアを持っていて、どれに取り組むかを決めるために、それぞれのアイデアを評価してほしいと頼んできました。
パートナーが提案したアイデアは次のとおりです。
バレンタインデーのアクティビティを選ぶための6つのタスクがあります。
パートナーが提案する各アイデアに対して、yes、no、maybeの3つのうちのどれかで答えます。
これらの選択肢を表すカスタム型Approvalを、次の3つのケースで定義します。Yes、No、Maybeです。
パートナーはレストランの候補を2つ選びました。1つは韓国料理、もう1つはトルコ料理です。
これらの料理を表すカスタム型Cuisineを、次の2つのケースで定義します。KoreanとTurkishです。
選べる映画は膨大にあるので、絞り込むために、パートナーはジャンルも挙げています。
次のジャンルをケースとして表すカスタム型Genreを定義します。Crime、Horror、Romance、Thrillerです。
先ほども触れましたが、パートナーは5つの異なるアクティビティを考えました。ボードゲームで遊ぶ、のんびり過ごす、映画を見る、レストランに行く、散歩するの5つです。
これらのアクティビティを表すカスタム型Activityを定義します。
BoardGame:関連するデータはありません。Chill:関連するデータはありません。Movie:関連データとしてGenreを持ちます。Restaurant:関連データとしてCuisineを持ちます。Walk:歩く距離をキロメートルで表すIntを関連データとして持ちます。最後に、パートナーのアイデアを評価する準備ができました。それぞれのアイデアに対して、次のように感じています。
Activityの値を受け取り、上記の気持ちに基づいてApprovalを返すrate_activityという関数を実装します。
rate_activity(Restaurant(Turkish))
// -> Maybe