2016-12-08 3 views
4

Ich versuche zu verwenden gdiff 1.1, eine generische diff-Bibliothek für Haskell, um einen Unterschied zwischen zwei Objekten zu erhalten, die zufällig eine Liste enthalten. Ich bin jedoch nicht in der Lage, es zur Arbeit zu bringen, und ich denke, es ist, weil ich nicht weiß, wie man die Instanz Type FooFamily für [FooEnvVar] definiert. Hier ist der Code, den ich bisher habe:Generische Diff von Objekten, die Listen mit Gdiff enthalten

module Main where 

import Data.Generic.Diff 

data Foo = Foo { fooEnv :: [FooEnvVar] } 
    deriving (Show, Eq) 

data FooStr = FooStr String 
    deriving (Show, Eq, Ord) 

data FooEnvVar = FooEnvVar { fooEnvName :: FooStr } 
    deriving (Show, Eq, Ord) 

data FooFamily :: * -> * -> * where 
    FooF :: FooFamily Foo (Cons [FooEnvVar] Nil) 
    FooStrF :: FooFamily FooStr (Cons String Nil) 

instance Family FooFamily where 
    decEq FooF FooF = Just (Refl, Refl) 
    decEq FooStrF FooStrF = Just (Refl, Refl) 
    decEq _ _ = Nothing 
    fields FooF (Foo fe) = Just (CCons fe CNil) 
    fields FooStrF (FooStr str) = Just (CCons str CNil) 
    apply FooF (CCons fe CNil) = Foo fe 
    apply FooStrF (CCons str CNil) = FooStr str 
    string FooF = "FooF" 
    string FooStrF = "FooStrF" 

instance Type FooFamily Foo where 
    constructors = [Concr FooF] 

instance Type FooFamily [FooEnvVar] where 
    constructors = [] -- what should I put here? 

main :: IO() 
main = 
    putStrLn $ show ((diff a b) :: EditScript FooFamily Foo Foo) 
    where 
    a = Foo [FooEnvVar (FooStr "hello"), FooEnvVar (FooStr "world")] 
    b = Foo [FooEnvVar (FooStr "hi"), FooEnvVar (FooStr "world")] 

Dieser Code kompiliert ohne Warnungen unter GHC 8.0.1 mit der -Wall Option. Wenn ich diesen Code ausführen, würde ich will, dass es die Unterschiede zwischen a und b, um zu zeigen, sondern es zeigt diese Ausgabe:

test_gdiff: Incorrect Family or Type instance. 
CallStack (from HasCallStack): 
    error, called at src/Data/Generic/Diff.hs:313:22 in gdiff-1.1-KTbM5AUQcBxD5ewDUGZ4O3:Data.Generic.Diff 

Falls es wichtig ist, ich mit diesen Erweiterungen der Haskell2010 Sprache verwenden: GADTs, LambdaCase, MultiParamTypeClasses, OverloadedStrings, FlexibleInstances.

Wie kann ich diesen Fehler beheben?

Antwort

2

Es gibt keine direkte Unterstützung für polymorphe Listen in gdiff.

Für jeden Typ, bei dem Sie eine Liste verwenden, müssen Sie den Listentyp und seine Konstruktoren ([], (:)) als Teile der Familie behandeln.

Hier sind Erklärungen, die für Ihr Beispiel sollte funktionieren:

data FooFamily :: * -> * -> * where 
    FooF  :: FooFamily Foo   (Cons [FooEnvVar] Nil) 
    FooEnvVarF :: FooFamily FooEnvVar (Cons FooStr Nil) 
    FooStrF :: FooFamily FooStr  (Cons String Nil) 
    NilF  :: FooFamily [FooEnvVar] Nil 
    ConsF  :: FooFamily [FooEnvVar] (Cons FooEnvVar (Cons [FooEnvVar] Nil)) 
    String  :: String -> FooFamily String Nil 

instance Family FooFamily where 
    decEq FooF FooF = Just (Refl, Refl) 
    decEq FooEnvVarF FooEnvVarF = Just (Refl, Refl) 
    decEq FooStrF FooStrF = Just (Refl, Refl) 
    decEq NilF NilF = Just (Refl, Refl) 
    decEq ConsF ConsF = Just (Refl, Refl) 
    decEq (String x) (String y) 
    | x == y = Just (Refl, Refl) 
    | otherwise = Nothing 
    decEq _ _ = Nothing 

    fields FooF (Foo fe) = Just (CCons fe CNil) 
    fields FooEnvVarF (FooEnvVar ev) = Just (CCons ev CNil) 
    fields FooStrF (FooStr x) = Just (CCons x CNil) 
    fields NilF [] = Just CNil 
    fields ConsF (x : xs) = Just (CCons x (CCons xs CNil)) 
    fields (String _) _ = Just CNil 
    fields _ _ = Nothing 

    apply FooF (CCons fe CNil) = Foo fe 
    apply FooEnvVarF (CCons ev CNil) = FooEnvVar ev 
    apply FooStrF (CCons x CNil) = FooStr x 
    apply NilF CNil = [] 
    apply ConsF (CCons x (CCons xs CNil)) = x : xs 
    apply (String x) CNil = x 

    string FooF = "FooF" 
    string FooEnvVarF = "FooEnvVarF" 
    string FooStrF = "FooStrF" 
    string NilF = "[]" 
    string ConsF = "(:)" 
    string (String x) = show x 

instance Type FooFamily Foo where 
    constructors = [Concr FooF] 

instance Type FooFamily [FooEnvVar] where 
    constructors = [Concr NilF, Concr ConsF] 

instance Type FooFamily FooEnvVar where 
    constructors = [Concr FooEnvVarF] 

instance Type FooFamily FooStr where 
    constructors = [Concr FooStrF] 

instance Type FooFamily String where 
    constructors = [Abstr String] 
Verwandte Themen