2012-03-15 3 views
4

У меня есть код на следующей схеме:Haskell: Использование одного класса в другой экземпляр

class First s where 
    func1 :: s -> s 
class Second a where 
    func2 :: s -> a s 

data D s = D {value :: s} 
myFunc2 :: First s => s -> D s 
myFunc2 = undefined 

В аргументе общих func2 не может быть экземпляром первой. Я хочу сделать D-экземпляр Second в только тех случаях, когда это значение экземпляра First. Тогда я хочу, чтобы получить этот экземпляр:

instance Second D where 
    func2 = myFunc2 

Но я получаю сообщение об ошибке:

No instance for (First s) 
    arising from a use of `myFunc2' 

Хорошо, пусть, например, быть:

instance First s => Second D where 
    func2 = myFunc2 

Но это дает ошибку:

Ambiguous constraint `First s' 
    At least one of the forall'd type variables mentioned by the constraint 
    must be reachable from the type after the '=>' 
In the instance declaration for `Second D' 

Итак, есть способ получить экземпляр класса с некоторыми условиями из других классов, но без всех переменных типа после '=>'?

ответ

7

Я думаю, что это помогает думать о том, что значит качественно

class Second a where 
    func2 :: s -> a s 

Second экземпляр обещает, что func2 определяется для любого типаs. Но это не относится к myFunc2, потому что myFunc2 определен только для тех s, для которых существует экземпляр First. Это означает, что, поскольку вы определили First и Second, невозможно использовать myFunc2 в экземпляре Second (если только не существует экземпляр forall s . First s catch-all, но я предполагаю, что нет, или вы бы не удосужились сделать класс типов).

Итак, вам нужно будет изменить хотя бы одну вещь. Вы можете переопределить Second, как предложил Гжегож. Если вам не нравится, что вы можете переопределить Second как

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FlexibleInstances #-} 

class Second a s where 
    func2 :: s -> a s 

instance First s => Second D s where 
    func2 = myFunc2 

Обратите внимание, что это говорит что-то другое, чем то, что вы написали изначально, потому что теперь Second экземпляр не гарантирует, что func2 является полиморфным. Но я думаю, что это ближе к тому, что вы имеете в виду, когда говорите: «Сделайте экземпляр D второго в только тех случаях, когда это значение экземпляра First». Возможно, это будет приемлемо в вашем коде.

+0

Спасибо, это похоже на лучшее, что я могу сделать. – spontaliku

6

Точное решение будет зависеть от того, какой код пытается сделать, но проблема в том, что тип подписи вы даете func2 не говоря уже о First s ограничение, в то время как ваше определение func2 для экземпляра Second D нужно. Следующие компилирует:

class First s where 
    func1 :: s -> s 
class Second a where 
    func2 :: First s => s -> a s 

data D s = D {value :: s} 
myFunc2 :: First s => s -> D s 
myFunc2 = undefined 

instance Second D where 
    func2 = myFunc2 
+0

Проблема заключается в том, что аргументы func2 не могут быть экземплярами First. Я хочу сделать D-экземпляр Second в только тех случаях, когда это значение экземпляра First. Я исправил вопрос. – spontaliku

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