幽霊型
PhantomType
以下の様な型の x
のこと
hsdata PhantomType x a = PhantomType a
左辺では2つの型変数を取るが、右辺では一つの型しか使っていない
使われていない型のことを幽霊型と呼ぶ
この例では x
何が嬉しいのか
こういう型を定義したときに
hsdata PhantomType x a = PhantomType a
こういうふうに型を別物として扱うことができる
hsdata PostId
data UserId
type UID = PhantomType UserId Int
type PID = PhantomType PostId Int
UID
も PID
も型のbodyは同じく PhantomType Int
である
であるにも関わらず UID
と PID
は全く別物として扱うことができる
仮に幽霊型を使っていなければ以下のようになる
hsdata Id a = Id a
type PostId = Int
type UserId = Int
type UID = Id UserId
type PID = Id PostId
PostId
も UserId
も実質 Int
なので、
UID
と PID
は両方とも実質 Id Int
となり、区別がつかない
どこで使えるのか
同じprimitiveな型だが区別したいときに使える
暗号文(Int)と平文(Int)
PostId(Int)とUserId(Int)
日付(String)
日付にも時間を含むものと、含まないものある
両方ともにStringだとうまく解析が出来なくてバグる
newtypeがあるのになぜ幽霊型が必要になる?
こうすると型のbodyが異なるものになっちゃうから?
hsnewtype PostId = PostId Int
newtype UserId = UserId Int
つまりbodyが異なるものでも良くて、primitiveな型を区別したいケースなら幽霊型は必要にならない
「幽霊型」の指すものが曖昧
定義: data PhantomType x a = PhantomTypeC a
使用: PhantomType X A
とするときに、
X
のことを幽霊型と呼ぶ派
PhantomType
のことを幽霊型と呼ぶ派
その他
などあって人によってバラバラ
言語別
TypeScript
Scala
Haskell
わかりやすいが、コメントでも指摘されている通り例が少し適切でない
OCaml
Elm
Rust
Swift
参考