开发者

Data.Data -- producing dataCast1 for an arity 2 type constructor (partially specialized)

So Data.Map has dataCast2 defined, which makes sense, as it has an arity 2 type constructor. dataCast1 defaults to const Nothing. dataCast2 is easily defined as gcast2.

For reference:

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))

The question at hand is this: given everything in Data.Data, Data.Typeable, etc., and given an arity 2 type constructor for which dataCast2 is defined (say, Map, or (,) ), is it possible to write a version of dataCast1 that does the right thing for a partial specialization of this type constructor, either for one specific constructor at a time, or in general?

Intuitively, I think there should be a good solution, but my first few tr开发者_JS百科ies crashed and burned.


I'm not sure if this is what you want, but it might steer you in the right direction if it's not. It is written in a very similar style to the gcast, gcast1, and gcast2 functions in the Data.Typeable library. For more details, "read the source, Luke".

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

Using this function you can, for instance write foo

foo :: Typeable d => c (d, a) -> Maybe (c (Int, a))
foo = myDataCast1


According to this paper the way to implement dataCast1 is either as

dataCast1 f = gcast1 f -- for unuary type constructors

or

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

They haven't said that this is the only way to implement it, but it might be the case. Perhaps it's worth asking the authors? I think the core problem is that we can't partially apply type constructors. e.g. the following is not possible

data T a b = ...

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

GHC will complain that T has not been applied to enough type arguments.

I can think of a work-around though. We define a newtype

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

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

It's pretty annoying but it does the job. But perhaps it doesn't fit with what you're trying to achieve.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜