2013-08-22 5 views
6

ハスケルでは、いくつかのタイプ制約を一緒にORする方法はありますか?それらのいずれかが満たされていれば、結合が満たされるようにしますか?型制約を結合する方法はありますか?

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE DataKinds #-} 
module Temp where 

data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black 

data Fruit (c :: Color) where 
    Banana :: (c ~ Green | c ~ Yellow | c ~ Black) => Fruit c 
    Apple :: (c ~ Red | c ~ Green)    => Fruit c 
    Grape :: (c ~ Red | c ~ Green | c ~ White)  => Fruit c 
    Orange :: (c ~ Tawny)       => Fruit c 

私ができる:例えば、私はGADTはDataKindによってパラメータ化していた、と私は特定の種類の特定のコンストラクタのための唯一の戻り値に、いくつかのコンストラクタを望んでいたと仮定し、擬似Haskellはなり

OR使って型クラスを実装しよう:

{-# LANGUAGE GADTs #-} 
{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE DataKinds #-} 
module Temp where 

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 BananaColor (c :: Color) 
instance BananaColor Green 
instance BananaColor Yellow 
instance BananaColor Black 

class AppleColor (c :: Color) 
instance AppleColor Red 
instance AppleColor Green 

class GrapeColor (c :: Color) 
instance GrapeColor Red 
instance GrapeColor Green 
instance GrapeColor White 

class OrangeColor (c :: Color) 
instance OrangeColor Tawny 

だけでなく、これは冗長です、それはまた、私は、元組合が閉じられたことで意図したものとは少し異なるのですが、型クラスは、すべての開いています。

instance OrangeColor Blue 

を定義するから誰かを停止するには何もありませんそして、それはオープンなので、コンパイラは言われない限り[Apple, Grape, Banana]はタイプ[Fruit Green]でなければならないことを推測することができる方法はありません。

答えて

4

文字通り実装する方法や、残念ながら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 
0

以下は私の問題のエンコードです。主なアイデアは、

data Color = White | Red | Blue | Yellow | Green | Tawny | Purple | Black 

class Fruit a where 
    getColor :: a -> Color 

data Banana where 
    GreenBanana :: Banana 
    YellowBanana :: Banana 
    BlackBanana :: Banana 

instance Fruit Banana where 
    getColor GreenBanana = Green 
    getColor YellowBanana = Yellow 
    getColor BlackBanana = Black 

data Apple where 
    GreenApple :: Apple 
    RedApple :: Apple 

instance Fruit Apple where 
    getColor GreenApple = Green 
    getColor RedApple = Red 

あなたの質問の最後の行は、あなたが明らかにFruit Greenがあるべきであることを意味するタイプ[Fruit Green]の何かをしたいことを示している。このタイプのクラスを実装する型として果物の型クラスと様々な種類のフルーツを表現することです上記のコードでGreenとしてasは値コンストラクタです。私たちは、タイプとして以下に示すようなものGreenを行う必要があります。

data Red = Red 
data Green = Green 
data Black = Black 

data Fruit c where 
    GreenBanana :: Fruit Green 
    BlackBanana :: Fruit Black 
    RedApple :: Fruit Red 
    GreenApple :: Fruit Green 


greenFruits :: [Fruit Green] 
greenFruits = [GreenBanana, GreenApple] 
+0

をあなたは[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''型を定義する必要がなくなります。 –

関連する問題