2017-01-16 3 views
1

GHC拡張を使用して任意の長さのタプルに一般化する新しい型クラスを定義できますか?任意の長さのタプルにインスタンス定義を持つ新しい型クラス

PreludeとBase(いくつかのクラスは最大15要素のタプルをサポートしています。最大7つまで)の組み込みクラスの動作とこれらのクラスを拡張する可能性については、すでにいくつか質問があります。

前奏曲と基本行動:私は少し異なる質問をしてい Extend a Show instance to a Tuple of any size

Haskell Tuple Size Limit

が新しい定義でショーを拡張します。全く新しいタイプのクラスを作成している場合、任意の長さのタプルを処理するインスタンスルールを追加することは可能でしょうか(おそらくGHC拡張を使用します)。

ここに、PartialOrderというクラスの例があります。私は、次のルール

(a,b ... , z) <= (a1,b1, ... , z1) iff (a <= a1) && (b <= b1) && ... && (z <= z1) 

ここで、従来の「いくつかの任意のサイズまでのタプルのためのクラスを定義する」アプローチを使用して定義での私の最初の刺しだを使用して任意のサイズのタプルを部分的に比較することができるようにしたいです。

任意の長さのタプルをカバーするインスタンス定義を記述するために使用できるGHC拡張はありますか?

テンプレートハスケルや外部プログラムを使って定義を事前に生成できますが、C++テンプレートのようにオンデマンドで生成することはできません。

-- Sets equipped with the (is_subset) operation are an example of a 
-- partial order. 
-- 
-- {} < {a}  less than 
-- {} = {}  equal to 
-- {a, b} > {b} greater than 
-- {a} ~ {b}  incomparable 
-- 
-- in order to define a partial order we need a definition of (<=) 

data PartialOrdering = POLessThan | POGreaterThan | POEqual | POIncomparable deriving (Eq, Show) 

class PartialOrder a where 
    lessThanEq :: a -> a -> Bool 

instance PartialOrder PartialOrdering where 
    lessThanEq POIncomparable _ = False 
    lessThanEq _ POIncomparable = False 

    -- with incomparables dealt with... 
    lessThanEq POLessThan _ = True 

    lessThanEq POEqual POLessThan = False 
    lessThanEq POEqual _ = True 

    lessThanEq POGreaterThan POGreaterThan = True 
    lessThanEq POGreaterThan _ = False 


-- note this is different from the semantics for Ord applied to tuples, 
-- which uses lexicographic ordering. 
-- 
-- (a,b) is less than or equal to (c,d) iff 
-- a <= b and c <= d 

-- 2 element tuple 
instance (PartialOrder a, PartialOrder b) => PartialOrder (a, b) where 
    lessThanEq (a,b) (c,d) = (lessThanEq a c) && (lessThanEq b d) 

-- 3 element tuple 
instance (PartialOrder a, PartialOrder b, PartialOrder c) => PartialOrder (a, b, c) where 
    lessThanEq (a,b,c) (d,e,f) = (lessThanEq a d) && (lessThanEq b e) && (lessThanEq c f) 

-- 4 element tuple 
instance (PartialOrder a, PartialOrder b, PartialOrder c, PartialOrder d) => PartialOrder (a, b, c, d) where 
    lessThanEq (a,b,c,d) (e,f,g,h) = (lessThanEq a e) && (lessThanEq b f) && (lessThanEq c g) && (lessThanEq d h) 


-- etc. 


main = putStrLn "hi" 
+4

だけの提案:なぜあなたは長インデックスリストを使用していませんか?そのようなデータ型はタプルと同型である。 GADTを使用して定義するのは簡単です。 –

答えて

4

ハスペルのタプルタイプは、実際には互いに意識していません。ありがたいことに、具体的なケースについては、GHC.Genericsを使用して問題を解決できます。すると、タプルだけでなく製品タイプのPartialOrderクラスを実際に派生させることができます。セットアップそのすべてで

{-# LANGUAGE TypeOperators, DefaultSignatures, FlexibleContexts, 
      StandaloneDeriving, DeriveAnyClass 
    #-} 

import GHC.Generics 
import Data.Function (on) 

data PartialOrdering 
    = POLessThan | POGreaterThan | POEqual | POIncomparable deriving (Eq, Show) 

class PartialOrder a where 
    lessThanEq :: a -> a -> Bool 

    default lessThanEq :: (Generic a, GPartialOrder (Rep a)) => a -> a -> Bool 
    lessThanEq = gLessThanEq `on` from 


-- | Helper generic version of your class 
class GPartialOrder f where 
    gLessThanEq :: f a -> f a -> Bool 

-- | Product types 
instance (GPartialOrder a, GPartialOrder b) => GPartialOrder (a :*: b) where 
    gLessThanEq (a1 :*: b1) (a2 :*: b2) = gLessThanEq a1 a2 && gLessThanEq b1 b2 

-- | Unary type (empty product) 
instance GPartialOrder U1 where 
    gLessThanEq U1 U1 = True 

-- | Meta information on type 
instance (GPartialOrder a) => GPartialOrder (M1 i c a) where 
    gLessThanEq (M1 a1) (M1 a2) = gLessThanEq a1 a2 

-- | Single type 
instance (PartialOrder a) => GPartialOrder (K1 i a) where 
    gLessThanEq (K1 x1) (K1 x2) = lessThanEq x1 x2 

1は、(-XDeriveGenericで行うことができます)Genericを導出した場合、1は、自動的に(有効-XDeriveAnyClassで)あなたのクラスを派生させることができます。タプルの型はすでにジェネリックのインスタンスであるため、-XStandaloneDerivingでは、Partial Orderのインスタンスを遡及的に派生させることができます。その後

deriving instance (PartialOrder a, PartialOrder b) => PartialOrder (a,b) 
deriving instance (PartialOrder a, PartialOrder b, PartialOrder c) => PartialOrder (a,b,c) 
-- and so on... 

data MyProduct a b = MyProduct a b deriving (Generic, PartialOrder) 

以下の作業のすべての予想通り、あなたは、あなたのクラスを使用することができます。

ghci> (POLessThan, POLessThan) `lessThanEq` (POEqual, POEqual) 
True 
ghci> (POLessThan, POEqual) `lessThanEq` (POEqual, POEqual) 
True 
ghci> (POLessThan, POEqual) `lessThanEq` (POEqual, POLessThan) 
False 
関連する問題