2016-05-09 4 views
0

長さ2または3のタプルをとり、NumおよびOrdを派生する型を含むデータ型を作成したいとします。次に、タプルの長さに基づいてどの関数を使用するかを決定できるように、型クラスインスタンス内のこのタプルの長さをパターンマッチします。下記の非コンパイル可能な疑似コードを見てください。少なくとも2つの問題があります。インスタンス内のタプル長のハスケルパターン一致

  1. Dominatesは、私は、例えばタプルを取得する方法がわからない

  2. クラス導出ではありませんfitnessesを呼び出して、インスタンスでパターンマッチングが行われるときに変数をデータ型から取得します。

コード:

data Fits = I2 (Int, Int) | F2 (Float, Float) | I3 (Int, Int, Int) | F3 (Float, Float, Float) 

data Ind = Ind { fitnesses :: Fits 
       , otherInfo :: String 
       } deriving (Dominates) 

class Dominates a where 
    dominates :: a -> a -> bool 

instance Dominates Ind where 
    dominates [email protected](_,_) [email protected](_,_) = x `dominates2` y -- takes two tuples of length 2 
    dominates [email protected](_,_,_) [email protected](_,_,_) = x `dominates3` y -- takes two tuples of length 3 

を更新:

data Ind = Ind { fitnesses :: Fits 
       , otherInfo :: String 
       } 

instance Eq Ind where 
    (Ind{ fitnesses = I2 [email protected](a1,a2) }) == (Ind{ fitnesses = I2 [email protected](b1,b2) }) = indCmp2 x y == EQ 
instance Ord Ind where 
    (Ind{ fitnesses = I2 [email protected](a1,a2) }) `compare` (Ind{ fitnesses = I2 [email protected](b1,b2) }) = indCmp2 x y 

indCmp2 :: (Num a, Ord a) => (a, a) -> (a, a) -> Ordering 
indCmp2 x y 
    | a0 < b0 = LT 
    | a0 > b0 = GT 
    -- Can assume (fst x) == (fst y) beneath 
    | a1 < b1 = LT 
    | a1 > b1 = GT 
    | a1 == b1 = EQ 
    where 
    a0 = fst x 
    a1 = snd x 
    b0 = fst y 
    b1 = snd y 

これがコンパイルされます。 Ordだけが必要な場合、なぜEqのインスタンスを作成する必要がありますか? Eq-instanceがなければ、コンパイラは「(Eq Ind)のインスタンスはありません」と文句を言います。

答えて

2

2タプルと3タプルのインスタンスを提供できます。

しかし、これが実際に必要なのが不思議です。

代わりに、次のようにすべての可能な場合にパターンマッチングが必要です。ここでクラスは必要ありません。

dominates :: Ind -> Ind -> Bool 
dominates (Ind{ fitnesses = I2 (a1,a2) }) 
      (Ind{ fitnesses = I2 (b1,b2) }) = ... 
dominates (Ind{ fitnesses = F2 (a1,a2) }) 
      (Ind{ fitnesses = F2 (b1,b2) }) = ... 
dominates (Ind{ fitnesses = I3 (a1,a2,a3) }) 
      (Ind{ fitnesses = I3 (b1,b2,b3) }) = ... 
dominates (Ind{ fitnesses = F3 (a1,a2,a3) }) 
      (Ind{ fitnesses = F3 (b1,b2,b3) }) = ... 
dominates _ _ = error "incompatible Ind values!" 

例:

data Ind = Ind { fitnesses :: Fits 
       , otherInfo :: String 
       } -- no deriving Ord here, we want to define it manually 

instance Ord Ind where 
    (Ind{ fitnesses = I2 x }) `compare` (Ind{ fitnesses = I2 y }) = indCmp2 x y 
    -- other cases here 
+0

最初の例では 'Ind'レコードの' fitness'フィールドを抽出しません。インスタンスを使ってそれを行う方法はありますか?私はOrdのインスタンスを派生させたい。 – tsorn

+0

@tsornわかりません。 'x'が' Ind''型の値なら 'fitness x'はフィールドの値です。なぜあなたはここでクラスを使う必要がありますか? – chi

+0

最初の例では、 'Dominates'は' Ind'のインスタンスを持たないので、 'Ind'はそれを派生できません。 2番目の例はうまくいきますが、Ordを派生させたい場合はinstanceを使う必要があると思います。トップポストに別の例を追加しました。 – tsorn

関連する問題