2010-12-01 3 views
2

Так Data.Map имеет dataCast2, что имеет смысл, поскольку имеет конструктор типа arity 2. dataCast1 по умолчанию - const Nothing. dataCast2 легко определяется как gcast2.Data.Data - создание dataCast1 для конструктора типа arity 2 (частично специализированного)

Для справки:

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, которая делает правильную вещь для частичной специализации этого типа конструктора либо для одного конкретного конструктора за раз, либо вообще?

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

+0

Это похоже на интересную проблему, но я думаю, мне понадобится немного больше фона. Во-первых, вопрос. Что именно вы подразумеваете под «делает правильную вещь для частичного применения конструктора этого типа»? Конструкторы типов могут отображаться частично в заголовке объявления класса или экземпляра, однако в любом другом месте они должны быть полностью применены AFAIK. – 2010-12-01 01:21:16

+0

@Sean Хорошая точка. Я изменил его, чтобы прочитать «частичную специализацию». Дело в том, что вы можете вызвать `myDataCast1` с результатом` Maybe (c (Int, a)) `так же, как можно вызвать` dataCast1` с результатом `Maybe (c (Maybe a))`. – sclv 2010-12-01 02:04:57

ответ

1

Я не уверен, что это то, что вы хотите, но оно может направить вас в правильном направлении, если это не так. Он написан в очень схожем стиле с функциями 44. В качестве примера можно использовать функции 44. В качестве примера можно использовать функции библиотеки 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

Согласно этому paper пути реализации 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 

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

 Смежные вопросы

  • Нет связанных вопросов^_^