2016-06-27 8 views
3

Ich bin mir bewusst, dass you can add constraints on associated type families and data families. Damit werden die Einschränkungen für alle Instanzen Ihrer Klasse erzwungen.Ableitungsklasse Klassenbeschränkung bei Verwendung der zugehörigen Familien

Aber ich kann nicht herausfinden, wie diese Einschränkungen in Instanz Ableitung oder Funktion Deklarationen. Zum Beispiel versagt diese Codeprüfung eingeben:

{-# 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 

die Fehlermeldungen sind:

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. 

Was ist hier los? Gibt es einen Workaround, um mein gewünschtes Verhalten zu erhalten?

Antwort

5

Der Kern des Problems ist, dass nur FooT a gegeben, haben Sie nirgendwo das Eq Instanz Wörterbuch aus ziehen.

Die Abhilfe ist explizit in Ihrer typeclass Anforderung zu sein, um dadurch einen Ort, wo die Eq dict geleitet wird:

{-# 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 

Oder können Sie vermeiden, indem Sie die Verpackung, um den Eq (FooT a) Wörterbuch mit den CantInferEq verwenden UndecidableInstances mit Erbauer:

{-# LANGUAGE GADTs, StandaloneDeriving #-} 
data CantInferEq a where 
    CantInferEq :: (Eq (FooT a)) => FooT a -> CantInferEq a 
deriving instance Eq (CantInferEq a) 
Verwandte Themen