Elmのカスタム型は、決まった数の名前付きケースを表します。それぞれの値は、その名前付きケースのうちのちょうど1つに対応します。
カスタム型はtypeキーワードを使って定義し、必要な構文はごくわずかです。Elmプログラミングで最も重要なテクニックの1つであり、コード上で取りうる値を現実世界の有効な値と正確に一致させるために使います。そうすることで不正なデータが入り込む余地がなくなり、ありえない状態をコードで表現できないようにします。
type Season
= Spring
| Summer
| Autumn
| Winter
カスタム型の各ケースには、必要に応じてデータを紐付けられます。また、ケースごとに異なる型のデータを持たせられます。どのケースにもデータが紐付いていない場合、この判別共用体は、他の言語で一般に_列挙型_(または_enum_)と呼ばれるものに似ています。
type FlexibleNumber
= Integer Int
| Float Float
| Invalid
特定のケースの値を作るには、その名前(Spring)を参照する方法と、完全修飾名(Season.Spring)を参照する方法があります。名前で参照できるのは、そのケースが同じモジュールで定義されている場合、またはimport SeasonModule exposing (Season(..))形式の構文でインポートされている場合です。完全修飾名で参照できるのは、import SeasonModule exposing (Season)形式の構文でインポートされている場合です。
integerTwo = Integer 2
invalid = FlexibleNumber.Invalid
カスタム型は、Elmのあらゆるものと同様に_構造的等価性_を持ちます。つまり、同じケースで同じ(省略可能な)データを持つ2つの値は等価です。
カスタム型を扱う際に推奨される方法は、パターンマッチングです。
let describe flexibleNumber =
case flexibleNumber of
Integer i ->
"Integer: " ++ fromInt(i)
Float f ->
"Float: " ++ fromFloat(f)
Invalid ->
"Invalid"
この演習の舞台はバレンタインデーです。パートナーと一緒に何か素敵なことをしようと計画しています。パートナーはたくさんのアイデアを持っていて、どの活動をするかを決めるために、それらのアイデアを評価してほしいと頼んできました。
パートナーからは、次のようなアイデアが出ています。
バレンタインデーの活動を選ぶための、6つのタスクがあります。
パートナーが提案するそれぞれのアイデアに対して、はい・いいえ・たぶんの3つのうちのどれかで答えます。
これらの選択肢を表す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を関連データとして持ちます。最後に、パートナーのアイデアを評価する準備ができました。パートナーのアイデアに対する気持ちは次のとおりです。
Activityの値を受け取り、上記の気持ちに基づいてApprovalを返すrateActivityという関数を実装してください:
rateActivity (Restaurant Turkish)
-- => Maybe