2016-06-27 3 views
3

Мне известно, что you can add constraints on associated type families and data families. Это делает принудительные ограничения для всех экземпляров вашего класса.вызывать ограничение типа класса при использовании связанных семейств типов

Но я не могу понять, как вывести эти ограничения в объявления о деривации или функции экземпляра. Например, этот код не ввести проверки:

{-# LANGUAGE FlexibleContexts #-} 
{-# LANGUAGE TypeFamilies #-} 

import Data.Proxy (Proxy) 

class Eq (FooT a) => Foo a where 
    type FooT a :: * 

-- Can't infer it in an instance derivation 
data CantInferEq a = CantInferEq (FooT a) deriving Eq 

-- Also can't infer it in a function declaration. 
-- The Proxy is there to avoid non-injectivity issues. 
cantInferEq :: Proxy a -> FooT a -> FooT a -> Bool 
cantInferEq _ x y = x == y 

сообщения об ошибках:

Test.hs:11:52: No instance for (Eq (FooT a)) … 
     arising from the first field of ‘CantInferEq’ (type ‘FooT a’) 
    Possible fix: 
     use a standalone 'deriving instance' declaration, 
     so you can specify the instance context yourself 
    When deriving the instance for (Eq (CantInferEq a)) 

Test.hs:16:23: No instance for (Eq (FooT a)) arising from a use of ‘==’ … 
    In the expression: x == y 
    In an equation for ‘cantInferEq’: cantInferEq _ x y = x == y 

Compilation failed. 

Что здесь происходит? Есть ли способ обхода моего желаемого поведения?

ответ

5

Суть проблемы в том, что с учетом только FooT a, вы не можете извлечь словарь экземпляра Eq.

Обходной должно быть явным в ваших требований класса типов, тем самым местом, где передается Eq ДИКТ:

{-# LANGUAGE StandaloneDeriving, UndecidableInstances #-} 

data CantInferEq a = CantInferEq (FooT a)  
deriving instance (Eq (FooT a)) => Eq (CantInferEq a) 

cantInferEq :: (Eq (FooT a)) => Proxy a -> FooT a -> FooT a -> Bool 
cantInferEq _ x y = x == y 

Или вы можете избежать необходимости использовать UndecidableInstances путем упаковки вверх Eq (FooT a) словарь с CantInferEq конструктор:

{-# LANGUAGE GADTs, StandaloneDeriving #-} 
data CantInferEq a where 
    CantInferEq :: (Eq (FooT a)) => FooT a -> CantInferEq a 
deriving instance Eq (CantInferEq a) 
Смежные вопросы