2016-10-02 75 views
1

我覺得我要有效地做這樣的事情:哈斯克爾:指定滿足類型類的功能將需要一些特定類型的滿足約束

class (forall z. ListZip z) => PlaneZip p where... --functions using z excluded 

在短,但更確切地說,我想有

class A p where ... --definition excluded 
class C p where 
    foo :: (A z) => p (z a) -> a 
data Alpha a = ...definition excluded 
data Beta a = ...definition excluded 
instance A Alpha where --definition excluded 
bar :: Beta (Alpha a) -> a 
instance C Beta where 
    foo = bar 

這是不可能的,因爲foo必須允許z是什麼這是一個A,不Alpha明確。我怎麼做到這一點,強制foo必須採取一些A但不是任何A


更詳細地說,我有許多列表拉鍊,我想製作Comonad的實例。我沒有創建一個列表拉鍊類型,也沒有製作大量的包裝器,而是決定創建一個ListZip類,並創建多個類型的實例。也就是說,

class (Functor z) => ListZip z where 
    leftMv :: z a -> z a 
    rightMv :: z a -> z a --further functions excluded 

data ListZipInf a = ListZipInf ([a]) a ([a]) deriving (Show) 
instance ListZip ListZipInf where... --functions excluded 
data ListZipTorus a = ListZipTorus [a] a [a] deriving (Show) 
instance ListZip ListZipTorus where.. --functions excluded 

現在我想爲2D列表類似拉鍊 - 平面拉鍊 -

data PlaneZipInf a = PlaneZipInf (ListZipInf (ListZipInf a)) deriving (Show) 
data PlaneZipTorus a = PlaneZipTorus (ListZipTorus (ListZipTorus a)) deriving (Show) 

最後,我想做出類似平面拉鍊類型類,這將讓我有

class PlaneZip p where 
    unwrap :: (ListZip z) => p (z (z a)) -> z (z a) 
    counit :: (ListZip z, Comonad z) => p (z (z a)) -> a 
    counit p = 
    let zs = unwrap p 
     in extract $ extract zs 

然而,這並不工作,特別是:給定一個方法來「解包」飛機拉鍊構造一種方式來拉一個單一的元素,「專注」出這個名單拉鍊的默認實現,

instance PlaneZip PlaneZipInf where 
    unwrap (PlaneZipInf zs) = zs 

給我一個錯誤 - Could not deduce a ~ (ListZipInf (ListZipInf a)) 據預計,對於任何ListZip工作的功能,但我給它提供一個特定的功能。

我怎麼能表達,我想unwrap採取型p (z (z a)),其中z是某種類型的這是ListZip一個實例,併產生(z (z a))

感謝

+2

看起來你希望在PlaneZip類中有一個關聯類型,在PlaneZip中有一個超類約束,它聲明該類型必須是ListZip的一個實例。也許你甚至想'z'被存在量化。但是,我不確定'p(z(za)) - > z(za)'是否正確,因爲'\(PlaneZipInf zs) - > zs'類型爲'PlaneZipInf a - > ListZipInf(ListZipInf a)'這與上述類型不符。 – user2407038

回答

3

我可能會誤解你的問題,但在你的情況看來,你將永遠結束了從嵌套列表創建拉鍊拉鍊面。如果是這樣的話,似乎更明智。簡單地做一些這樣的:

{-# LANGUAGE StandaloneDeriving, FlexibleContexts, UndecidableInstances #-} 

data PlaneZip z a = PlaneZipInf (z (z a)) 
deriving instance (Show a, Show (z a), Show (z (z a))) => Show (PlaneZip z a) 

type PlaneZipInf a = PlaneZip ListZipInf a 
type PlaneZipTorus a = PlaneZip ListZipTorus a 

unwrap :: PlaneZip z a -> z (z a) 
unwrap (PlaneZip zs) = zs 

counit :: Comonad z => PlaneZip z a -> a 
counit p = 
    let zs = unwrap p 
     in extract $ extract zs 

如果你真的想確保在PlaneZip z az總是一個ListZip,你可以使用下面的GADT而不是

{-# LANGUAGE GADTs #-} 
data PlaneZip z a where 
    PlaneZip :: ListZip z => z (z a) -> PlaneZip z a 

如果不是這種情況,請隨時回覆 - 我相信還有其他的東西,可能在這裏與associated type families做,但上面的解決方案要好得多。

+0

這很接近,但我認爲我的問題出現了,因爲我想讓PlaneZipInf和PlaneZipTorus滿足各種類型類,所以它們必須是實際的新類型,而不僅僅是別名。 – drowdemon

1

簡單製作z這個類的參數怎麼樣?

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} 

class (ListZip z, Comonad z) => PlaneZip p z | p -> z where 
    unwrap :: p (z (z a)) -> z (z a) 
    counit :: p (z (z a)) -> a 
    counit p = 
    let zs = unwrap p 
     in extract $ extract zs 

instance PlaneZip PlaneZipInf ListZipInf where 
    unwrap (PlaneZipInf zs) = zs 

| p -> z語法是函數依賴;這意味着zp決定,因此也有instance PlaneZip PlaneZipInf SomeOtherType也是非法的。

相關問題