2012-12-17 219 views
2

那麼,什麼將是很好的,如果你可以做類似下面的(不一定是這種格式,只是一般的想法):嵌套/分數據類型

data Sub = SubA | SubB 
data Super = Sub | SuperB 

isSub :: Super -> Bool 
isSub Sub = True 
isSub _ = False 

所以isSub蘇巴將報告真(而不是一個錯誤。) 在你可能會做這樣的事情的時刻:

data Super = SubA | SubB | SuperB 

isSub :: Super -> Bool 
isSub SubA = True 
isSub SubB = True 
isSub _ = False 

它不可怕或任何東西,但它不能很好地擴展(如如果子最多時SubZ這將是可怕的笨重),它不允許你將Sub類型添加到它們自己的type-cl中屁股。爲了避免這個問題,你可以用子:

data Sub = SubA | SubB 
data Super = SuperA Sub | SuperB 

isSub :: Super -> Bool 
isSub (SuperA _) = True 
isSub _ = False 

但現在你必須確保你的包裹替補使用他們作爲一個超級......再也不可怕;只是沒有真正表達我想要的語義(即Super可以是任何Sub或SuperB)。第一個(合法的)例子是「Super可以是SubA ...」,第二個是「Super可以是SuperA,需要Sub ...」

EDTI:更改一些名稱以避免與音樂內容混淆。

P.S.從技術上講,當我開始思考如何在Haskell中表示Scheme的數字塔時...但我更感興趣的是表示「Type1可以是任何Type2加x,y ...」的更一般問題。

+0

基於答案波紋管他們的意見:它看起來像,出口最上面的類型與一些輔助功能,以從下類型創建該類型是要對這個的最佳方式。 –

+0

儘管看起來您需要爲您的輸入類型設置類型類(所以如果是SubA Int,SubB Float和SuperB String;那麼您將需要一個用於Int和Float的SubInput類實例和一個SuperInput類實例對於Int,Float和String)。至少,這些類可以是空的。但是,你可以有mkSub :: SubInput a => a - >超級 –

+0

那麼,你的問題是什麼? :) –

回答

0

它不可怕或任何東西,但它不能很好地擴展

,如果你使用一些模板哈斯克爾這將是罰款。我想看看derive工具的makeIs日常指導。

但現在你必須做確保包裹你的潛艇使用他們作爲超級

不,類型系統會告訴你,如果你忘了。舉例來說,如果你有

data Super = Sub Sub | Super 
data Sub = SubA | SubB 

然後在其中使用Sub而是奢望一段Super會被抓住的任何背景。我猜你已經知道你的意思是什麼?

+0

不,這就是我的意思。類型系統會告訴你,但你仍然必須這樣做(只是一個措辭的差異。)這是一種令人討厭的,你必須在香草哈斯克爾包裝Sub類型,但我想如果我這樣做更多我不會介意使用模板Haskell ... –

+0

您可以使用'mkSuper'方法創建'CanBeSuper'類。例如''實例CanBeSuper超級其中mkSuper = id'和'實例CanBeSuper Sub其中mkSuper = Sub'。然後你需要做的就是將'mkSuper'應用於參數 - where子句或者'ViewPatterns'擴展將是最好的。這些函數會看起來像'someFunc(mkSuper - > s)= ...'。 –

+0

我通常對使用擴展猶豫不決,但對於類型類的想法很有趣。我打算玩這個想法一會兒,看看當我去3或4個嵌套子類型時會發生什麼。 –

0

你不能有像

data Sub = SubA | SubB 
data Super = Sub | SuperB 

任何假設上面的語法是允許的,那麼問題就給出的值構造SubA你不能告訴它的類型是SubSuper。這就是爲什麼你需要在構造函數中包裝你的類型。

對於你的第二個例子,你所做的事情應該是默認的做法,但你可以做一些簡單的操作,儘管我不建議這樣做,因爲使用show會慢很多。你可以嘗試一些類似於此的其他黑客攻擊。

import Data.List 
data Super = SubA | SubB | SuperB deriving Show 
isSub :: Super -> Bool 
isSub m = isPrefixOf "Sub" (show m) 

如果你真的想有一些像上面最好是像你這樣定義的功能。使用TH可能會節省您的時間。

你的第三種情況是我真正推薦的做法。你需要有一個像SuperA這樣的包裝器構造器,因爲我上面講過的原因。這就是爲什麼你不能確切地說type1是type2加x,y,z。最接近的事情是將元素包裝在構造函數中或使用類型類型。

data Sub = SubA | SubB 
data Sup = SuperA | SuperB 

class Super a where 
    isSub :: a -> Bool 
    isSub _ = True 

instance Super Sup where 
    isSub _ = False 

instance Super Sub 

data SupSup = SuperSuperA | SuperSuperB 

class SuperSuper a where 
    isSuper :: a -> Bool 
    isSuper _ = True 


instance SuperSuper SupSup where 
    isSuper _ = False 

instance SuperSuper Sup 
instance SuperSuper Sub 

你能想到的在這裏Super(這是一個類型類,而不是一個類型)包含Sub和額外成才(Sup)。

+0

從技術上講,SubA既是Sub也是Super。但是,這使我們更多地進入了一個基於集合的類型系統... 使用類型類似的1個問題將是從深度2到深度3結束了很多額外的工作(包裝isn儘管如此,還是好多了。) –

+0

技術上,haskell語義不允許SubA屬於這兩種類型。你可以檢查使用相同的構造函數聲明兩種數據類型。我沒有看到任何包裝問題。如果您害怕進行更深層次的修改,您可以使用'lens'。 – Satvik

+0

我知道,我只是說你需要一個基於集合的類型系統來表達SubA作爲Sub和Super(Haskell沒有)。包裝也沒什麼問題,這是我認爲的最好的做法。我只是好奇其他方式來做到這一點(例如,我正在努力想出一個類型級的實現;所以感謝拼寫出來......仍想着如何很好地擴展它,而不必結束每種類型和類型組合) –

0

您可能想使用鏡頭(Control.Lens)庫及其實例的Data.Data和Data.Typleable。鏡頭是嘗試在列表,元組和所有其他數據類型中解決這些類型的多級問題。

>data Sub = SubA | SubB deriving (Show, Data, Typeable, Eq) 
>data Super = SuperA Sub | SuperB deriving (Show, Data, Typeable, Eq) 

-- A little bit of a hack, there is probably a better way of doing this 
>isSub' :: Sub -> Bool 
>isSub' x = typeOf x == typeOf SubA 

>tmp1 = SuperA SubA 
>tmp2 = SuperA SubB 

>isSub x = anyOf biplate (isSub') x 

>isSub tmp1 
True 
>issub tmp2 
True 

isSub真的太籠統了,它檢查是否有任何提供的數據類型的子類型是Sub。所以如果你有一棵樹,樹上是一個Sub,那麼它就是真的。應該可以將其限制爲僅限於您的用例。

鏡頭庫的優點是現在我可以添加另一個層到類型層次結構。

>data SuperSuper = SuperSuperA Super | SuperSuperB | SuperSuperC Sub deriving (Show,Data,Typeable) 

>tmp3 = SuperSuperA (SuperA SubA) 
>tmp4 = SuperSuperC SubB 

>isSub tmp3 
True 
>isSub tmp4 
True