2015-03-05 3 views
3

Например:Как я могу связать контекст типа в объявлении экземпляра класса?

let context = sequence [classP (mkName "Eq") [varT (mkName "a")]] 
in 
    [d| instance $(context) => Bar (Foo a) where 
     quux _ = undefined 
    |] 

Результат, который я хочу instance Eq a => Bar (Foo a) where quux _ = undefined, однако, Template Haskell жалуется, справедливо, что context имеет тип Q Cxt вместо ожидаемого Q Type.

Есть ли способ указать ограничения объявления экземпляра без необходимости напрямую использовать конструктор InstanceD?

+2

Естественно, если TH ожидает TypeQ, вы должны дать ему TypeQ. Я думал, что вы сможете изменить 'context' на' conT '' Eq \ 'appT \' varT (mkName "a") '- это просто создает TypeQ. Однако, когда я пытаюсь скомпилировать его, я получаю сообщение об ошибке, которое я никогда не видел до этого момента: «Экзотический тип предиката (пока) не обрабатывается Template Haskell $ context'. Похоже, вам не повезло. – user2407038

ответ

1

Я не думаю, что Template Haskell в настоящее время поддерживает контексты типа сращивания напрямую (это всего лишь предположение).

Однако, вы можете определить функцию для добавления контекстов всех DecsQ класса типов экземпляров:

appendInstancesCxtQ :: DecsQ -> Q Cxt -> DecsQ 
appendInstancesCxtQ = liftM2 $ \ds c -> map (`appendInstanceCxt` c) ds 
    where appendInstanceCxt (InstanceD c ts ds) c' = InstanceD (c++c') ts ds 
     appendInstanceCxt d     _ = d 

Затем, вы можете использовать его, чтобы изменить результат квази цитируемое выражения:

let v = varT $ mkName "a" 
    context = sequence [[t| Eq $v |]] 
in 
    [d| instance Bar (Foo $v) where 
     quux _ = undefined 
    |] `appendInstancesCxtQ` context 

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