2015-09-09 43 views
4

我想什麼,能夠做的就是像下面這樣:使用IxSet,我可以圍繞任意可索引類型構建一個可索引包裝器嗎?

import Data.IxSet 

newtype Key a = Key Integer 
    deriving (Eq, Ord, Show) 

data Keyed a = Keyed { key :: (Key a), value :: a } 
    deriving (Eq, Ord, Show) 

instance Indexable a => Indexable (Keyed a) 
    where empty = ixSet $ ixFun (\k -> [key k]) : _somehow_reuse_indices_of_a_ 

的想法是,如果一些數據結構是可轉位,我應該能夠索引Keyed由同一類型的包裝它(加上Key a索引)。

應該很容易轉換傳遞給ixFun在包裝類型的指數與Keyed,而不是a工作職能:只是value組成。但我找不到任何實際獲得這些功能的方法。

我也看過ixset類型的包;那裏的Indexable版本實際上提供了一個索引列表,而不是一個空的IxSet。這似乎更適合於重用索引,但「索引列表」是一種不導出其構造函數的自定義類型,所以我似乎無法得到它們。

我錯過了任何支持這種用法的東西嗎?

回答

3

ixset庫似乎將「密鑰生成函數」與「索引」相混淆,這使得Indexable類比作者可能想要的更強大。 (特別是,empty允許已經有一些元素 - 這使得名稱empty有點奇怪!)您可以通過引入一個僅用於函數的新類型來解決此客戶端問題因此不能包含任何元素):

data IxFun a = forall key. (Typeable key, Ord key) => IxFun (a -> [key]) 

ixFun' :: (Typeable key, Ord key) => (a -> [key]) -> IxFun a 
ixFun' = IxFun 

instance Contravariant IxFun where 
    contramap f (IxFun g) = IxFun (g . f) 

ixFromIxFun :: IxFun a -> Ix a 
ixFromIxFun (IxFun f) = ixFun f 

然後你就可以建立一些類型類支持,如:

class IndexableFun a where funs :: [IxFun a] 

-- turn any IndexableFun into an Indexable 
defaultEmpty :: IndexableFun a => IxSet a 
defaultEmpty = ixSet (map ixFromIxFun funs) 

這個類的實例看起來非常相似的Indexable實例,但不是empty = ixSet [ixFun foo, ...]你現在寫funs = [ixFun' foo, ...]。現在很容易寫您的實例:

instance (IndexableFun a, Typeable a) => IndexableFun (Keyed a) where 
    funs = ixFun' (\v -> [key v]) : map (contramap value) funs 

instance (IndexableFun a, Typeable a) => Indexable (Keyed a) where 
    empty = defaultEmpty 

你甚至可以很容易適應的ixGen實施這種類型:

ixGen' :: forall proxy a b. (Data a, Ord b, Typeable b) => proxy b -> IxFun a 
ixGen' _ = ixFun' (flatten :: a -> [b]) 

集成這種方式進入ixset包本身將是一個非常很好的接觸,並不應該太難。儘管首先聯繫維護者,因爲這可能會帶來一些有意義的變化:人們可能想要修改類本身,而不是像上面描述的那樣創建一個錯綜複雜的額外類加默認實例設置,不能向後兼容。

+0

是的,類似的東西就是我的備份計劃。它不允許我重用現有的'Indexable'實例,但實際上我沒有立即使用它。你是對的,它出來相當不錯;也許我會看看是否可以將它包含在上游。 – Ben

相關問題