判別共用体は、決まった数の名前付きケースを表す型です。判別共用体の各値は、名前付きケースのうちのちょうど1つに対応します。
判別共用体はtypeキーワードを使って定義し、各ケースはパイプ(|)文字で区切ります。
type Season =
| Spring
| Summer
| Autumn
| Winter
判別共用体の各ケースには、必要に応じてデータを関連付けることができ、ケースごとに異なる型のデータを持たせることができます。どのケースにもデータが関連付けられていない場合、判別共用体は、他の言語で一般に_列挙型_(または_enum_)と呼ばれるものに似ています。
type Number =
| Integer of int
| Float of float
| Invalid
特定のケースの値を作るには、その名前(例えばSuccess)を参照します。ケース名は単なるコンストラクター関数なので、関連するデータは通常の関数の引数として渡すことができます。別の判別共用体が同じ名前のケースを定義している場合は、その完全な名前(例えばResult.Success)を使う必要があります。
let byName = Integer 2
let byFullName = Number.Invalid
判別共用体には_構造的等価性_があり、同じケースで同じ(省略可能な)データを持つ2つの値は等価であることを意味します。
判別共用体を扱うのにif/elif/else式を使うこともできますが、推奨される方法は、_識別子パターン_を使ったパターンマッチングです。
let describe number =
match number with
| Integer i -> sprintf "Integer: %d" i
| Float d -> sprintf "Float: %f" d
| Invalid -> "Invalid"
この演習では、バレンタインデーにパートナーと一緒に何か楽しいことをする予定です。パートナーはたくさんのアイデアを持っていて、どの活動をするかを決めるために、それぞれのアイデアを評価してほしいと言っています。
パートナーが提案しているアイデアは次のとおりです。
バレンタインデーの過ごし方を選ぶためのタスクが6つあります。
パートナーが提案するアイデアそれぞれに対して、3つの選択肢のいずれかで答えます。yes、no、maybeです。
Approvalという判別共用体を定義して、これらの選択肢を次の3つのケースで表しましょう。Yes、No、Maybeです。
パートナーは候補のレストランを2つ選びました。1つは韓国料理、もう1つはトルコ料理です。
Cuisineという判別共用体を定義して、これらの料理を次の2つのケースで表しましょう。KoreanとTurkishです。
選べる映画は山ほどあるので、候補を絞るために、パートナーはジャンルも挙げてくれています。
Genreという判別共用体を定義して、次のジャンルをケースとして表しましょう。Crime、Horror、Romance、Thrillerです。
すでに触れたとおり、パートナーは5つのアクティビティを考えました。ボードゲームで遊ぶ、のんびり過ごす、映画を観る、レストランに行く、散歩するです。
Activityという判別共用体を定義して、これらのアクティビティの種類を表しましょう。
BoardGame: 関連するデータはありません。Chill: 関連するデータはありません。Movie: Genreを関連するデータとして持ちます。Restaurant: Cuisineを関連するデータとして持ちます。Walk: 歩く距離をキロメートルで表すintを関連するデータとして持ちます。いよいよ、パートナーのアイデアを評価する準備ができました。パートナーのアイデアに対する気持ちは次のとおりです。
Activityの値を受け取って、上記の気持ちに基づいてApprovalを返す、rateActivityという名前の関数を実装しましょう。
rateActivity (Restaurant Turkish)
// => Maybe