2013-07-01 7 views
11

型を型クラスの一部にすることは可能ですか?何かのように:ハスケル:型式(型格)を定義できます

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

タイプの家族はあなたが探している正確に何ですが、functional dependenciesとその機能、すなわちmulti-parameter type classesを達成するための別の方法もあります。これらの拡張機能を使用すると、コードは次のようになります。

ここ
{-# 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

ありがとうございました!もう1つの答えは質問のタイトルに直接結びついていますが、あなたの解決策も同様です。 –

+0

私は、MPTC + FDが複雑な依存関係を持ついくつかのエッジのケースではTFよりも表現力があったという印象を受けました... –