Data.Data - создание dataCast1 для конструктора типа arity 2 (частично специализированного) - PullRequest
2 голосов
/ 01 декабря 2010

Итак, в Data.Map определено dataCast2, что имеет смысл, так как имеет конструктор типа arity 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 и т. Д. И дан конструктор типа arity 2, для которого определен dataCast2 (скажем, Map или (,)) Можно ли написать версию dataCast1, которая делает правильную вещь для частичной специализации этого конструктора типа, либо для одного конкретного конструктора за раз, либо в целом?

Интуитивно, я думаю, что должно быть хорошее решение, но мои первые несколько попыток потерпели неудачу.

Ответы [ 2 ]

1 голос
/ 01 декабря 2010

Я не уверен, что это то, что вы хотите, но это может направить вас в правильном направлении, если это не так. Он написан в стиле, очень похожем на функции gcast, gcast1 и gcast2 в библиотеке Data.Typeable. Для получения более подробной информации, «читайте источник, Люк».

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
0 голосов
/ 20 декабря 2010

Согласно этой статье способ реализации 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 PairInt a = PairInt (Int, a) deriving Typeable

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

Это довольно раздражает, но это делает работу. Но, возможно, это не соответствует тому, чего вы пытаетесь достичь.

...