16

私はこのようなGADTを持っています:

data In a where
  M :: MVar a -> In a
  T :: TVar a -> In a
  F :: (a -> b) -> In a -> In b

さまざまな入力プリミティブをラップしますが、最後のコンストラクターではFunctorインスタンスも使用できます。

instance Functor In where
  fmap f (F g v) = F (f . g) v
  fmap f x = F f x

このタイプのポイント、ところで、サポートすることです:

read :: In a -> IO a
read (M v) = takeMVar v
read (T v) = atomically (readTVar v)
read (F f v) = f <$> read v

私ができるようにしたいのは、このタイプの明白なEqインスタンスを次のように定義することです。

instance Eq (In a) where
  (M x) == (M y) = x == y
  (T x) == (T y) = x == y
  (F _ x) == (F _ y) = x == y
  _ == _ = False

問題は3番目のケースです。これは、xとyがその時点で必ずしも同じタイプであるとは限らないため、失敗します。という事は承知しています。私自身のコードでは、長い回避策を講じることができますが、Eqを直接定義する方法があるはずだと感じています。私の考えでは、解決策は「MまたはTに到達するまで、Fコンストラクターをドリルスルーし続け、それらが同じコンストラクター(つまり、両方ともMまたは両方のT)であり、同じタイプである場合は、同等性の比較を行う」のようなものですが、私はどうやってそれを書くことができるかわかりません。

4

2 に答える 2

11

Fの半分しかテストしないので、私はあなたの平等について非常に疑っていますが、それが本当に必要な場合は、次の方法でそれを行うことができます。a内部で存在記号化されたタイプが同じである場合にのみ2つのFを比較できるため、キャストはタイプの同等性のテストとして機能することに注意してください。

data In a where
  M :: MVar a -> In a
  T :: TVar a -> In a
  F :: (Typeable a) => (a -> b) -> In a -> In b
  deriving (Typeable)


instance Eq (In a) where
  (M x) == (M y) = x == y
  (T x) == (T y) = x == y
  (F _ x) == (F _ y) = Just x == cast y
  _ == _ = False

または多分これはあなたが望むものではありませんか?In Intモチベーションをもう一度読むと、anが。に等しくなる関数が必要なようですIn Double

これら2つをどのように比較F floor rしますかF id r(もしそうならrM x :: In Double

于 2011-05-17T10:39:46.953 に答える
9

ある時点で、異なるタイプの2つのものが等しいかどうかをテストする必要があります。これを行うには2つの方法があります。

  1. Typeableクラス。
  2. GADT data Equal a b where Eq :: Equal a a

MVar2をサポートしてTVarいないため、クラスを使用する必要がありますTypeableTypeableつまり、制約を使用してデータ型を拡張する必要があります。

幸いなことに、制約をどこに置くかについてはある程度の自由があります。たとえば、次のように配置できます。

data In a where
    M :: Typeable a => MVar a -> In a
    T :: Typeable a => TVar a -> In a
    F :: (a -> b) -> In a -> In b

equal :: In a -> In b -> Bool
equal (M x) (M y)     = Just x == cast y
equal (T x) (T y)     = Just x == cast y
equal (F _ x) (F _ y) = x `equal` y
equal _ _             = False

instance Eq (In a) where
    (==) = equal

このようにして、Functorインスタンスを保持することができます。

于 2011-05-17T12:20:54.213 に答える