単純な値のモデリング
ProductCode や OrderId など、同じ int でも互換性があるわけではない。
そこで、型が異なるのを明確にするため、プリミティブな表現をラップする。
code:fsharp
type CustomerId = CustomerId of int
ケース名をコンストラクタ関数として使うことで、値を生成できる
code:fsharp
let customerId = CustomerId 42
誤って異なる型を混同することがなくなる
code:fsharp
type CustomerId = CustomerId of int
type OrderId = OrderId of int
let customerId = CustomerId 42
let orderId = OrderId 42
printfn "%b" (orderId = customerId) // コンパイルエラー
code:fsharp
let processCustomerId (id : CustomerId) = ...
processCustomerId orderId // コンパイルエラー
アンラップ するには、ケースラベルを使ってパターンマッチを行う code:fsharp
let customerId = CustomerId 42
let (CustomerId innerValue) = customerId
printfn "%i" innerValue // 42
関数定義のパラメータで直接アンラップすることも可能
code:fsharp
// val processCustomerId: CustomerId -> unit
let processCustomerId = (CustomerId innerValue) =
printfn "innerValue is %i" innerValue
パフォーマンスの問題
単純型は、メモリ使用量と効率性が犠牲になる
アプリケーションの種類によっては注意する必要がある
単純型の代替策
オーバーヘッドはないが、型の安全性は下がる
code:fsharp
type UnitQuantity = int
オーバーヘッドは残るが、配列に格納する際には、連続したメモリ領域が使用され、キャッシュ効率が良い
code:fsharp
type UnitQuantity = UnitQuantity of int
単純型のコレクションではなく、プリミティブ値のコレクション全体を 1 つの型として定義する
code:fsharp
type UnitQuantities = UnitQuantities of int[]
パフォーマンスチューニングについて
一般的には、まず最も分かりやすい方法で ドメイン をモデリングし、その後でチューニングや最適化に取り組む