2013-07-01 111 views
11

是否有可能讓某個類型成爲類型類的一部分?例如:Haskell:類型類是否可以定義類型(ala類型特徵)

class KeyTraits v where 
    keyType :: * 
    key :: v -> keyType 

data TableRow = { date :: Date, metaData :: String, value :: Int } 

instance KeyTraits TableRow where 
    keyType = Date 
    key = date 

而且這些「類型級別」函數可以用在其他地方嗎?例如:

-- automatically deduce the type for the key, from the value type, using 
-- the typeclass 
data MyMap v = { getMap :: (KeyTraits v) => Map (keyType) v } 

我可能會做一些完全錯誤的,但我基本上要定義像上面的(例如某些值已經可以具有可以被用作主要數據)型關係的能力。如果這是不可能的,或者是困難的,你能否提出一個比較習慣的更好的設計?

謝謝!

回答

26

看看type families

{-# LANGUAGE TypeFamilies #-} 
{-# LANGUAGE RankNTypes #-} 

class KeyTraits k where 
    type KeyType k :: * 
    key :: v -> KeyType k 

data TableRow = TableRow { date :: Date, metaData :: String, value :: Int } 

instance KeyTraits TableRow where 
    type KeyType TableRow = Date 
    key = date 

data MyMap v = MyMap { getMap :: (KeyTraits v) => Map (KeyType v) v } 
11

類型的家庭是你在尋找什麼,但也有另一種方式來實現其功能,即multi-parameter type classesfunctional dependencies。有了這些擴展你的代碼看起來是這樣的:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} 

class KeyTraits v k | v -> k where 
    key :: v -> k 

data TableRow = { date :: Date, metaData :: String, value :: Int } 

instance KeyTraits TableRow Date where 
    key = date 

這裏相關類型遷移到類型的類參數,並vk,以前隱性的關係,現在變成明確的功能性依賴。

這與關聯類型完全等價,但IMO提供了更清晰的語法,特別是在使用類型類的函數中。比較:

getMap :: (KeyTraits v) => Map (KeyType v) v 

getMap :: (KeyTraits k v) => Map k v 

當多種類型和多種類型的類出現在單個類型聲明,這變得更加明顯。

但是,類型族似乎被haskell社區所青睞,實際上整個擴展比MPTC + FD更強大,因爲類型族可以在沒有類型類的情況下聲明,並且還有數據族。

+0

非常感謝您的選擇!儘管其他答案與問題標題更直接相關,但您的解決方案同樣重要。 –

+0

我的印象是MPTC + FD在複雜依賴的邊緣情況下比TF更具表現力...... –