文字通り実装する方法や、残念ながらConstraint
を実装する方法は考えられませんが、あなたの例のように均等である場合は、型クラスのアプローチを盛り上げてタイプファミリーで閉じられ、ブール値を解除しました。これはGHC 7.6以降でのみ有効です。最後に、GHC 7.8でどのようにうまくいくのか、それをGHC 7.4にバックポートする方法の両方について言及します。
考えはこれです:私たちは値レベルの機能isBananaColor :: Color -> Bool
を宣言する可能性が同じようなので、あまりにも我々はタイプレベルの機能IsBananaColor :: Color -> Bool
宣言することができます。
type family IsBananaColor (c :: Color) :: Bool
type instance IsBananaColor Green = True
type instance IsBananaColor Yellow = True
type instance IsBananaColor Black = True
type instance IsBananaColor White = False
type instance IsBananaColor Red = False
type instance IsBananaColor Blue = False
type instance IsBananaColor Tawny = False
type instance IsBananaColor Purple = False
を私たちが好きなら、私たちも
を追加することができます
type BananaColor c = IsBananaColor c ~ True
私たちは、その後、すべての果実の色のためにこれを繰り返し、2番目の例のようにFruit
を定義します。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black
data Fruit (c :: Color) where
Banana :: BananaColor c => Fruit c
Apple :: AppleColor c => Fruit c
Grape :: GrapeColor c => Fruit c
Orange :: OrangeColor c => Fruit c
type family IsBananaColor (c :: Color) :: Bool
type instance IsBananaColor Green = True
type instance IsBananaColor Yellow = True
type instance IsBananaColor Black = True
type instance IsBananaColor White = False
type instance IsBananaColor Red = False
type instance IsBananaColor Blue = False
type instance IsBananaColor Tawny = False
type instance IsBananaColor Purple = False
type BananaColor c = IsBananaColor c ~ True
type family IsAppleColor (c :: Color) :: Bool
type instance IsAppleColor Red = True
type instance IsAppleColor Green = True
type instance IsAppleColor White = False
type instance IsAppleColor Blue = False
type instance IsAppleColor Yellow = False
type instance IsAppleColor Tawny = False
type instance IsAppleColor Purple = False
type instance IsAppleColor Black = False
type AppleColor c = IsAppleColor c ~ True
type family IsGrapeColor (c :: Color) :: Bool
type instance IsGrapeColor Red = True
type instance IsGrapeColor Green = True
type instance IsGrapeColor White = True
type instance IsGrapeColor Blue = False
type instance IsGrapeColor Yellow = False
type instance IsGrapeColor Tawny = False
type instance IsGrapeColor Purple = False
type instance IsGrapeColor Black = False
type GrapeColor c = IsGrapeColor c ~ True
-- For consistency
type family IsOrangeColor (c :: Color) :: Bool
type instance IsOrangeColor Tawny = True
type instance IsOrangeColor White = False
type instance IsOrangeColor Red = False
type instance IsOrangeColor Blue = False
type instance IsOrangeColor Yellow = False
type instance IsOrangeColor Green = False
type instance IsOrangeColor Purple = False
type instance IsOrangeColor Black = False
type OrangeColor c = IsOrangeColor c ~ True
(必要であれば、あなたは-XConstraintKinds
を取り除くとtype XYZColor c = IsXYZColor c ~ True
種類、およびちょうどXYZ :: IsXYZColor c ~ True => Fruit c
としてFruit
のコンストラクタを定義する得ることができます。)
さて、何これはあなたを購入し、それはあなたを購入していないものを?プラス面では、あなたが望むようにあなたのタイプを定義する能力を得ますが、それは間違いなく勝利です。 Color
が閉じられているので、誰もタイプファミリーインスタンスを追加してこれを破ることはできません。
しかし、欠点があります。 [Apple, Grape, Banana]
のタイプがFruit Green
であることを自動的に伝えたいという推論は得られません。さらに悪いのは、[Apple, Grape, Banana]
が完全に有効なタイプ(AppleColor c, GrapeColor c, BananaColor c) => [Fruit c]
を持っているということです。はい、これを単体化する方法はありませんが、GHCはそれを理解できません。完璧に正直なところ、これらのプロパティを提供するソリューションは想像できませんが、私はいつも驚いています。このソリューションのもう1つの明らかな問題は、どのようにの長さがであるかです。IsXYZColor
タイプのファミリーごとに8つのカラーケースをすべて定義する必要があります。 (それぞれのブランドの新しいタイプの家族の使用にも迷惑が、この形式のソリューションを避けられない。)
は、私はそのGHC 7前述しました。8はこれをより良くする予定です。すべての単一のケースをすべてのIsXYZColor
クラスごとにリストする必要性を取り除くことで、それを実現します。どうやって?まあ、Richard Eisenberg などは、GHC HEADにという閉じたオーバラップオーダータイプファミリーを導入し、7.8で利用可能になります。トピックにはa paper in sumbission to POPL 2014(およびextended version)があります。また、リチャード氏はan introductory blog post(旧式の構文があるようです)と書いています。
考え方型のインスタンスを通常の関数のように宣言することができます。方程式はすべて1つの場所で宣言されていなければなりません。なぜならIsBananaColor Green
マッチの両方の最初と最後の方程式
type family IsBananaColor (c :: Color) :: Bool
type instance IsBananaColor Green = True
type instance IsBananaColor Yellow = True
type instance IsBananaColor Black = True
type instance IsBananaColor c = False
のようなものは、あいまいです。しかし、通常の関数ではうまくいくはずです。だから、新しい構文は次のとおりです。
type family IsBananaColor (c :: Color) :: Bool where
IsBananaColor Green = True
IsBananaColor Yellow = True
IsBananaColor Black = True
IsBananaColor c = False
type family ... where { ... }
ブロックが型家族にあなたががそれを定義したい方法を定義します。上記のように、この型のファミリが閉じられ、順序付けられ、重複していることを通知します。したがって、コードはGHC 7.8で、次の(私はそれが私のマシンにインストールされていないとして、テストされていない)のようなものになるだろう:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black
data Fruit (c :: Color) where
Banana :: IsBananaColor c ~ True => Fruit c
Apple :: IsAppleColor c ~ True => Fruit c
Grape :: IsGrapeColor c ~ True => Fruit c
Orange :: IsOrangeColor c ~ True => Fruit c
type family IsBananaColor (c :: Color) :: Bool where
IsBananaColor Green = True
IsBananaColor Yellow = True
IsBananaColor Black = True
IsBananaColor c = False
type family IsAppleColor (c :: Color) :: Bool where
IsAppleColor Red = True
IsAppleColor Green = True
IsAppleColor c = False
type IsGrapeColor (c :: Color) :: Bool where
IsGrapeColor Red = True
IsGrapeColor Green = True
IsGrapeColor White = True
IsGrapeColor c = False
type family IsOrangeColor (c :: Color) :: Bool where
IsOrangeColor Tawny = True
IsOrangeColor c = False
万歳、私たちは退屈から眠りに落ちることなくこれを読むことができます!実際には、私はこのコードの明示的なIsXYZColor c ~ True
バージョンに切り替えました。私はそれをしました。余分な4つのタイプの同義語のための定型文が、これらのより短い定義ではっきりと迷惑になったからです!
しかし、反対の方向に進み、このコードを醜いものにしましょう。どうして?さて、GHC 7.4(これは、私のマシン上にまだ残っているものです)は、*
結果タイプのタイプファミリをサポートしていません。代わりに何をすることができますか?型クラスと関数の依存関係を使ってそれを偽造することができます。考え方は、IsBananaColor :: Color -> Bool
の代わりにタイプクラスIsBananaColor :: Color -> Bool -> Constraint
があり、色からブール値への関数依存性を追加するという考え方です。その後、IsBananaColor c b
はより良いバージョンのIsBananaColor c ~ b
の場合にのみ満たされます。 Color
が閉じられており、関数の依存関係がありますが、これは同じプロパティを提供しますが、概念的にはそれほど醜いです。さらに邪魔することなく、完全なコード:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleContexts #-}
data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black
data Fruit (c :: Color) where
Banana :: BananaColor c => Fruit c
Apple :: AppleColor c => Fruit c
Grape :: GrapeColor c => Fruit c
Orange :: OrangeColor c => Fruit c
class IsBananaColor (c :: Color) (b :: Bool) | c -> b
instance IsBananaColor Green True
instance IsBananaColor Yellow True
instance IsBananaColor Black True
instance IsBananaColor White False
instance IsBananaColor Red False
instance IsBananaColor Blue False
instance IsBananaColor Tawny False
instance IsBananaColor Purple False
type BananaColor c = IsBananaColor c True
class IsAppleColor (c :: Color) (b :: Bool) | c -> b
instance IsAppleColor Red True
instance IsAppleColor Green True
instance IsAppleColor White False
instance IsAppleColor Blue False
instance IsAppleColor Yellow False
instance IsAppleColor Tawny False
instance IsAppleColor Purple False
instance IsAppleColor Black False
type AppleColor c = IsAppleColor c True
class IsGrapeColor (c :: Color) (b :: Bool) | c -> b
instance IsGrapeColor Red True
instance IsGrapeColor Green True
instance IsGrapeColor White True
instance IsGrapeColor Blue False
instance IsGrapeColor Yellow False
instance IsGrapeColor Tawny False
instance IsGrapeColor Purple False
instance IsGrapeColor Black False
type GrapeColor c = IsGrapeColor c True
class IsOrangeColor (c :: Color) (b :: Bool) | c -> b
instance IsOrangeColor Tawny True
instance IsOrangeColor White False
instance IsOrangeColor Red False
instance IsOrangeColor Blue False
instance IsOrangeColor Yellow False
instance IsOrangeColor Green False
instance IsOrangeColor Purple False
instance IsOrangeColor Black False
type OrangeColor c = IsOrangeColor c True
をあなたは[GHC 7.4 + 'sの種類のプロモーション機能](http://www.haskell.org/ghc/docs/7.6を見たことがあります。 1/html/users_guide/promotion.html)?型を型として扱い、値を型として扱うことができます。 '-XDataKinds'を使うと、' Green'は完全に有効なタイプレベルの種類の 'Color'です。これにより、タイプレベルのプログラミングはより安全になります( 'Fruit Int'はよく書かれているようにコード化されているので)、' 'Data Green = Green''型を定義する必要がなくなります。 –