2

したがって、Data.Map はdataCast2定義されています。これは、アリティ 2 型のコンストラクターを持っているため、理にかなっています。dataCast1デフォルトはconst Nothingです。dataCast2として簡単に定義されgcast2ます。

参考のため:

class Typeable a => Data a where
    dataCast1 :: Typeable1 t => (forall d. Data d => c (t d)) -> Maybe (c a)
    dataCast2 :: Typeable2 t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c a)
    ...

gcast1 :: (Typeable1 t, Typeable1 t') => c (t a) -> Maybe (c (t' a))
gcast2 :: (Typeable2 t, Typeable2 t') => c (t a b) -> Maybe (c (t' a b))

Data.Data当面の問題は、次のとおりです。 、Data.Typeableなどのすべてが与えられ、アリティ 2 型のコンストラクタdataCast2が定義されている場合 (たとえば、Map、または)、部分的な特殊化に対して正しいことを行う(,)バージョンを作成することは可能ですか?dataCast1一度に 1 つの特定のコンストラクターに対して、または一般的に、この型コンストラクターの

直観的には、良い解決策があるはずだと思いますが、最初の数回はクラッシュして燃えました。

4

2 に答える 2

1

これがあなたが望むものかどうかはわかりませんが、そうでない場合は正しい方向に導くかもしれません. これは、Data.Typeable ライブラリのgcastgcast1、および関数と非常によく似たスタイルで記述されています。gcast2詳細については、「ソースを読んでください、ルーク」.

myDataCast1 :: forall c t d e a.(Typeable d, Typeable e) => c (t d a) -> Maybe (c (t e a))
myDataCast1 x = r
   where
     r = case typeOf (getArg x) == typeOf (getArg (fromJust r)) of
           True  -> Just $ unsafeCoerce x
           False -> Nothing
     getArg :: c (t x a) -> x
     getArg = undefined

この関数を使用すると、たとえば次のように書くことができますfoo

foo :: Typeable d => c (d, a) -> Maybe (c (Int, a))
foo = myDataCast1
于 2010-12-01T04:04:49.857 に答える
0

この論文によると、dataCast1 を実装する方法は次のいずれかです。

dataCast1 f = gcast1 f -- for unuary type constructors

また

dataCast1 f = Nothing -- for non-unary type constructors

これが唯一の実装方法だとは言っていませんが、そうかもしれません。おそらく、著者に尋ねる価値はありますか?核となる問題は、型コンストラクターを部分的に適用できないことだと思います。たとえば、次のことはできません

data T a b = ...

instance Typeable a => Data (T Int) where
   dataCast1 f = ...

GHC は、 T が十分な型引数に適用されていないと文句を言うでしょう。

私は回避策を考えることができます。newtype を定義します

newtype PairInt a = PairInt (Int, a) deriving Typeable

instance (Typeable a, Data a) => Data (PairInt a) where
  dataCast1 f = gcast1 f

それはかなり面倒ですが、それは仕事をします。しかし、おそらくそれはあなたが達成しようとしているものと一致しません。

于 2010-12-20T04:32:54.183 に答える