3

次のように、一般的な Pair 型クラスのインスタンスとして、Cantor Pairing Function を実装しようとしています。

module Pair (Pair, CantorPair) where

-- Pair interface
class Pair p where
    pi :: a -> a -> p a
    k :: p a -> a
    l :: p a -> a

-- Wrapper for typing
newtype CantorPair a = P { unP :: a }

-- Assume two functions with signatures:
cantorPair :: Integral a => a -> a -> CantorPair a
cantorUnpair :: Integral a => CantorPair a -> (a, a)

-- I need to somehow add an Integral a constraint to this instance,
-- but I can't work out how to do it.
instance Pair CantorPair where
    pi = cantorPair
    k = fst . cantorUnpair
    l = snd . cantorUnpair

インスタンスに適切な Integral 制約を追加するにはどうすればよいですか? Pair インターフェイス自体を変更する必要があるかもしれないという漠然とした気持ちがありますが、これをどうやって行うのかわかりません。

4

3 に答える 3

2

クラス定義にアクセスできる場合は、、、およびメソッドにIntegral制約を追加できます。ただし、これは少し不十分です。これがすべてのインスタンスに対して正しい制約になるということは何もありません。結局のところ、十分な先見性がないという理由だけでいくつかのインスタンスを拒否したくはありません。したがって、ここに 1 つの一般化があります。各インスタンスで制約を変更できるようにします。piklIntegral

{-# LANGUAGE ConstraintKinds, TypeFamilies #-}
import GHC.Exts

newtype CantorPair a = P { unP :: a }
cantorPair :: Integral a => a -> a -> CantorPair a
cantorUnpair :: Integral a => CantorPair a -> (a, a)
cantorPair = undefined
cantorUnpair = undefined

class Pair p where
    type Ctxt p a :: Constraint
    pi :: Ctxt p a => a -> a -> p a
    k  :: Ctxt p a => p a -> a
    l  :: Ctxt p a => p a -> a

instance Pair CantorPair where
    type Ctxt CantorPair a = Integral a
    pi = cantorPair
    k  = fst . cantorUnpair
    l  = snd . cantorUnpair

-- just for fun
data DataPair a = DataPair a a

instance Pair DataPair where
    type Ctxt DataPair a = ()
    pi = DataPair
    k (DataPair a _) = a
    l (DataPair _ a) = a

-- this one made GHC panic! neat, I get to file a bug
data Unit a = Unit

instance Pair Unit where
    type Ctxt Unit a = a ~ ()
    pi _ _ = Unit
    k _ = ()
    l _ = ()
于 2012-09-13T03:33:08.677 に答える
1

すべてのペアに常に整数要素を含める必要がありますか?この場合、メソッドのシグニチャに制約を追加できます。

class Pair p where
  pi :: Integral i => i -> i -> p i
  k :: Integral i => p i -> i
  l :: Integral i => p i -> i

これにより、ペアクラスの一般性が低下しますが、CantorPairタイプがその一部になる可能性があります。

クラスをある程度一般的にしたい場合Pairは、マルチパラメータタイプのクラスを使用できます。(これには2つの拡張子が必要です:MultiParamTypeClassesFlexibleInstances。)

class Pair p a where
  pi :: a -> a -> p a
  k :: p a -> a
  l :: p a -> a

instance Integral i => Pair CantorPair i where
    pi = cantorPair
    k = fst . cantorUnpair
    l = snd . cantorUnpair

これが設計の観点から必ずしも最良のオプションであるかどうかはわかりませんが、マルチパラメーター型クラスがどのように機能するかを学ぶための良い方法です。(確かに、これはかなり単純です。)

于 2012-09-13T00:28:48.947 に答える
1

このソリューションは型ファミリを使用するため、必要-XTypeFamiliesです。型コンストラクターではなく、型自体に型制約を置きます。

class Pair p where
    type First p :: *
    type Second p :: *
    pi :: First p -> Second p -> p
    k :: p -> First p
    l :: p -> Second p

次に、次のようなインスタンスを作成します。

instance Integral a => Pair (CantorPair a) where
    type First (CantorPair a) = a
    type Second (CantorPair a) = a
    pi = cantorPair
    k = fst . cantorUnpair
    l = snd . cantorUnpair

instance Pair (a, b) where
    type First (a, b) = a
    type Second (a, b) = b
    pi = (,)
    k = fst
    l = snd
于 2012-09-13T00:49:22.123 に答える