我正在尝试使用 gdiff 1.1(Haskell的通用差异库)来区分碰巧包含列表的两个对象。但是,我无法让它工作,我认为这是因为我不知道如何为Type FooFamily
定义[FooEnvVar]
的实例。这是我到目前为止的代码:
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")]
此代码使用-Wall
选项在GHC 8.0.1下编译时没有任何警告。当我运行此代码时,我希望它显示a
和b
之间的差异,但它会显示此输出:
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
如果重要,我使用带有这些扩展的Haskell2010语言:GADT,LambdaCase,MultiParamTypeClasses,OverloadedStrings,FlexibleInstances。
如何解决此错误?
答案 0 :(得分:2)
gdiff中没有对多态列表的直接支持。
对于您使用列表的每种类型,您必须将列表类型及其构造函数([]
,(:)
)视为系列的一部分。
以下是适用于您的示例的声明:
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]